Pictures from the network, if violated your rights, please contact me.

preface

Xdebug should be familiar to many people, debugging and installation is a bit cumbersome, but it is very easy to use.

Docker and Swoole are also popular in recent years, but they are not easy to debug. Many people’s first reaction to the headline is “Isn’t Swoole not compatible with Xdebug?” Yes, Swoole’s official documentation clearly states that Swoole is not compatible with Xdebug.

However, the strong community gave us the answer: SDEBUG

Sdebug is a tool forked from Xdebug 2.7 that can be used for breakpoints and debugging in Swoole environments.

Runtime environment

software version
Windows 10 Professional 1909
PHPStorm 2020.1
Docker Desktop 2.2.0.5 (43884).
Docker 19.03.8
Hyper-V latest
Hyperf (PHP Framework) 1.1.25 (hyperf – skeleton create)
Sdebug 2.7
PHP 7.3.12

Start the installation

Docker && Docker Desktop

Docker can be downloaded from the official website for Windows, but note the following restrictions.

  • 64-bit operating system
  • More than 4G RAM
  • Enable virtualization in the BIOS
  • Windows Professional and above
  • Open the Hyper – V

I’m not going to go into the introduction here because there are too many articles like this, so make sure Docker is installed.

When the installation is complete, a little static Docker icon will appear on your desktop taskbar. Notice, I want to emphasize that static static means Docker is running, dynamic means Docker is in a medium not running state. Then right click, select Settings, we need to open two options.

  • 1. Enable the TCP connection

  • 2. Set up the domestic Docker Hub image

{
  "registry-mirrors": [
    "http://hub-mirror.c.163.com"]."insecure-registries": []."debug": true."experimental": false
}
Copy the code

Now, select Apply & Restart in the lower right corner and wait for the Docker to Restart. If the Docker does not Restart, you can manually click Restart in the Docker icon in the taskbar. After the Restart is complete, execute the command to check.

$docker info Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: http://hub-mirror.c.163.com/ Live Restore Enabled: false Product License: Community EngineCopy the code

You should now be able to see the mirror address of NetEase.

Let’s start

Check the connection

The important factor for debugging is whether the Docker container can communicate with the host. Otherwise, the following is nonsense.

Use PowersShell or Cmder

$cat C: / Windows/System32 / drivers/etc/hosts | findstr searches the host. The docker. Internal 192.168.3.22 host. The docker. InternalCopy the code

After executing, you should see an IP 192.168.x.x output mapped to host.docker.internal. Please remember this IP. Now run the following command, run a Alpine Linux container, and run a ping, but you won’t see the output here.

  • Further reading

Networking features in Docker Desktop for Windows | Docker Documentation

$ docker run -di alpine:latest
a8369f4e057e161c2079281e4bfbc31dc509f802e3ce0c2f09708cd8613459ae
Copy the code

We then execute the following command to obtain the container ID, which we already obtained after the previous execution.

$ docker ps
CONTAINER ID        IMAGE               COMMAND               CREATED              STATUS              PORTS               NAMES
a8369f4e057e        alpine:latest       "/bin/sh"   About a minute ago   Up About a minute                       pensive_lehmann
Copy the code

Use Docker Exec to open the command line that can interact with the container.

$ docker exec -it a8369f4e057e sh
Copy the code

Docker exec it

/bin/bash docker exec it

/bin/bash docker exec it

/bin/bash After entering the terminal, we re-execute the ping command.


/ # ping 192.168.3.22 (192.168.3.22): 56 data bytes 64 bytes from 192.168.3.22: Seq =0 TTL =37 time=1.003 ms 64 bytes from 192.168.3.22: seq=1 TTL =37 time=0.937 ms 64 bytes from 192.168.3.22: seq=1 TTL =37 time=0.937 ms 64 bytes from 192.168.3.22: Seq =2 TTL =37 time=1.026 ms 64 bytes from 192.168.3.22: Seq =3 TTL =37 time= 1.341 ms ^C -- 192.168.3.22 Ping statistics -- 3 packets transmitted, 4 packets transmitted, 0% packet loss round-trip min/ AVG/Max = 0.937/1.026/1.141msCopy the code

If a normal ping message can be output, it means that our docker container can communicate with the host. If not, try ping 192.168.56.1. If these two commands can’t ping, I think you don’t need to see 😨, because the basic is to do the Docker container internal communication with the host machine, to use Xdebug, if you just want to build a development environment, then you can continue to see.

Next, I will show you how to build your own Docker PHP development environment using Dockerfile.

Docker

Installing PHP

Most of the time, I use the latest VERSION of PHP for development, unless the project calls for an older version, which is the case here. Because Sdebug is based on Xdebug 2.7, which does not support the latest PHP 7.4, So we had to go to the Docker Hub PHP Library and select a newer PHP tag :7.3.17- CLI-alpine3.11. Create a new php.dockerfile file and install the necessary extensions and Composer.

FROM php:7.3.17-cli-alpine3.11
Now we need to configure something.
# compile parameter, used to specify the Swoole version
ARG swoole_ver
# save to environment variable, if not passed to default value
ENV SWOOLE_VER=${swoole_ver:-"v4.4.15"}

# APk is a package manager for Alpine
# set-ex is to stop the script in case of an error
RUN set -ex \
    Do all this in a temporary directory
    && cd /tmp \
    # change the default apK source to the Aliyun image
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    Update package list
    && apk update \
    # Add so many extensions because we'll need them later to compile Swoole and sdebug
    && apk add vim git autoconf openssl-dev build-base zlib-dev re2c libpng-dev oniguruma-dev

# install composer
RUN cd /tmp \
    # Download Composer from Aliyun
    && wget https://mirrors.aliyun.com/composer/composer.phar \
    && chmod u+x composer.phar \
    && mv composer.phar /usr/local/bin/composer \
    # Set aliyun image for Composer
    && composer config -g repo.packagist composer https://mirrors.aliyun.com/composer \
    Add the composer global command to PATH to make sure we use it later
    && echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc

# php ext
RUN php -m \
    # docker-php-ext-install # docker-php-ext-install is a PHP directive that allows us to install some default PHP extensions
    You can enable the necessary extensions here
    && docker-php-ext-install gd pdo_mysql mysqli sockets pcntl \
    Now you can check the extensions that PHP already has installed
    && php -m
Copy the code

So our image is ready to run PHP, but next we need to install Swoole.

Install Swoole

If you have used PECL, you may know that Swoole and PhpRedis can be installed directly with PECL, but PECL installation is slow to download, so we use Swoole’s official warehouse in China.

# install swoole
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/swoole/swoole swoole \
    && cd swoole \
    # Switch to the specified version of the tag
    && git checkout ${SWOOLE_VER} \
    && phpize \
    Run configure
    && ./configure --enable-openssl --enable-sockets --enable-http2 --enable-mysqlnd \
    && make \
    && make install \
    # enable the extension via docker-php-ext-enable, which is also provided by PHP.
    && docker-php-ext-enable swoole \
    Check PHP modules already installed
    && php -m \
    Check whether swoole is installed correctly
    && php --ri swoole
Copy the code

Install Sdebug

Sdebug source code is hosted on Github. As we all know, Github download speed is slow due to some reasons, so we need to use the domestic mirror, but it seems that Sdebug does not have a mirror in China, so we need to do it ourselves, go to the code cloud, register an account, Then select the new project to import from Github so that we can create a mirror of the repository. I have already created a Sdebug, you can create one yourself if you mind, the method is above. The procedure for installing Sdebug is almost exactly the same as Swoole, but there are a few points to note, which I’ll comment in detail in Dockerfile next

# install sdebug
Change the directory to/TMP before running clone
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/vyi/sdebug sdebug \
    Go to the clone directory
    && cd sdebug \
    Switch to the sdebug_2_7 branch, this must be the switch branch, because the master branch is the source of Xdebug
    && git checkout sdebug_2_7 \
    && phpize \
    && ./configure --enable-xdebug \
    && make \
    && make install \
    # here is the value xdebug executed after the installation is complete
    && docker-php-ext-enable xdebug \
    && php -m \
    Sdebug = sdebug
    && php --ri sdebug

Copy the code

Now that everything is installed, we need to do some simple configuration for Swoole and sdebug, and just like before, Here is using Dockerfile commands/usr/local/etc/PHP/conf. D, this position is the default PHP ini loading directory will scan, we can execute PHP – ini command to check

/mnt/d/htdocs/tom # php --ini
Configuration File (php.ini) Path: /usr/local/etc/php
Loaded Configuration File:         (none)
Scan for additional .ini files in: /usr/local/etc/php/conf.d
Additional .ini files parsed:      /usr/local/etc/php/conf.d/99-xdebug-enable.ini,
/usr/local/etc/php/conf.d/docker-php-ext-gd.ini,
/usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pcntl.ini,
/usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini,
/usr/local/etc/php/conf.d/docker-php-ext-redis.ini,
/usr/local/etc/php/conf.d/docker-php-ext-sockets.ini,
/usr/local/etc/php/conf.d/docker-php-ext-sodium.ini,
/usr/local/etc/php/conf.d/docker-php-ext-swoole.ini,
/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
Copy the code

You can see the following, which means he will scan the configuration file here

Scan for additional .ini files in: /usr/local/etc/php/conf.d

# config php
RUN cd /usr/local/etc/php/conf.d \
    # swoole config
    # Turn off swoole short name, use Hyperf this is required
    && echo "swoole.use_shortname = off" >> 99-off-swoole-shortname.ini \
    # config xdebug&& {\# Add an Xdebug node
        echo "[Xdebug]"; \
        # Enable remote connection
        echo "xdebug.remote_enable = 1"; \
        # This is a multi-user debugging, but now some difficulties, temporarily do not start
        echo "; xdebug.remote_connect_back = On"; \
        Start remote debugging automatically
        echo "xdebug.remote_autostart = true"; \
        Host. Docker. Internal.
        echo "xdebug.remote_host = host.docker.internal"; \
        The port is fixed to 19000. Of course, other ports can be filled in to ensure that they are not occupied
        echo "xdebug.remote_port = 19000"; \
        # Here is fixed
        echo "xdebug.idekey=PHPSTORM"; \
        Save the result to 99-xdebug-enable.ini
    } | tee 99-xdebug-enable.ini

Copy the code

Host. Docker. Internal and 19000 are necessary, the host points to the host, the port is the port on which PHP Storm listens, docker needs to send requests to it, so it needs to make sure it is not occupied.

  • Further reading

Networking features in Docker Desktop for Windows | Docker Documentation

Install PhpRedis

Use this extension because your project needs to connect to Redis, which is just a connection library, not Redis.

# install phpredis
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/mirrors/phpredis phpredis \
    && cd phpredis \
    && phpize \
    && ./configure \
    && make \
    && make install \
    && docker-php-ext-enable redis \
    && php -m \
    && php --ri redis

Copy the code

Miscellaneous configuration

# check
Check PHP version information and installed modules
RUN cd /tmp \
    Check the PHP version
    && php -v \
    Check the installed modules
    && php -m \
    && echo -e "Build Completed!"

Expose port 9501
EXPOSE 9501
The default login directory does not exist.
# We need to map our external Windows file directory to the Docker container during run
WORKDIR /mnt/d/htdocs
Copy the code

Dockerfile

Our Dockerfile should now look like this

FROM php:7.3.17-cli-alpine3.11
Now we need to configure something.
# compile parameter, used to specify the Swoole version
ARG swoole_ver
# save to environment variable, if not passed to default value
ENV SWOOLE_VER=${swoole_ver:-"v4.4.15"}

# APk is a package manager for Alpine
# set-ex is to stop the script in case of an error
RUN set -ex \
    Do all this in a temporary directory
    && cd /tmp \
    # change the default apK source to the Aliyun image
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    Update package list
    && apk update \
    # Add so many extensions because we'll need them later to compile Swoole and sdebug
    && apk add vim git autoconf openssl-dev build-base zlib-dev re2c libpng-dev oniguruma-dev

# install composer
RUN cd /tmp \
    # Download Composer from Aliyun
    && wget https://mirrors.aliyun.com/composer/composer.phar \
    && chmod u+x composer.phar \
    && mv composer.phar /usr/local/bin/composer \
    # Set aliyun image for Composer
    && composer config -g repo.packagist composer https://mirrors.aliyun.com/composer \
    Add the composer global command to PATH to make sure we use it later
    && echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc

# php ext
RUN php -m \
    # docker-php-ext-install # docker-php-ext-install is a PHP directive that allows us to install some default PHP extensions
    You can enable the necessary extensions here
    && docker-php-ext-install gd pdo_mysql mysqli sockets pcntl \
    Now you can check the extensions that PHP already has installed
    && php -m


# install swoole
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/swoole/swoole swoole \
    && cd swoole \
    # Switch to the specified version of the tag
    && git checkout ${SWOOLE_VER} \
    && phpize \
    Run configure
    && ./configure --enable-openssl --enable-sockets --enable-http2 --enable-mysqlnd \
    && make \
    && make install \
    # enable the extension via docker-php-ext-enable, which is also provided by PHP.
    && docker-php-ext-enable swoole \
    Check PHP modules already installed
    && php -m \
    Check whether swoole is installed correctly
    && php --ri swoole

# install sdebug
Change the directory to/TMP before running clone
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/vyi/sdebug sdebug \
    Go to the clone directory
    && cd sdebug \
    Switch to the sdebug_2_7 branch, this must be the switch branch, because the master branch is the source of Xdebug
    && git checkout sdebug_2_7 \
    && phpize \
    && ./configure --enable-xdebug \
    && make \
    && make install \
    # here is the value xdebug executed after the installation is complete
    && docker-php-ext-enable xdebug \
    && php -m \
    Sdebug = sdebug
    && php --ri sdebug


# config php
RUN cd /usr/local/etc/php/conf.d \
    # swoole config
    # Turn off swoole short name, use Hyperf this is required
    && echo "swoole.use_shortname = off" >> 99-off-swoole-shortname.ini \
    # config xdebug&& {\# Add an Xdebug node
        echo "[Xdebug]"; \
        # Enable remote connection
        echo "xdebug.remote_enable = 1"; \
        # This is a multi-user debugging, but now some difficulties, temporarily do not start
        echo "; xdebug.remote_connect_back = On"; \
        Start remote debugging automatically
        echo "xdebug.remote_autostart = true"; \
        Host. Docker. Internal.
        echo "xdebug.remote_host = host.docker.internal"; \
        The port is fixed to 19000. Of course, other ports can be filled in to ensure that they are not occupied
        echo "xdebug.remote_port = 19000"; \
        # Here is fixed
        echo "xdebug.idekey=PHPSTORM"; \
        Save the result to 99-xdebug-enable.ini
    } | tee 99-xdebug-enable.ini


# install phpredis
RUN cd /tmp \
    # from mirrors
    && git clone https://gitee.com/mirrors/phpredis phpredis \
    && cd phpredis \
    && phpize \
    && ./configure \
    && make \
    && make install \
    && docker-php-ext-enable redis \
    && php -m \
    && php --ri redis


# check
Check PHP version information and installed modules
RUN cd /tmp \
    Check the PHP version
    && php -v \
    Check the installed modules
    && php -m \
    && echo -e "Build Completed!"

Expose port 9501
EXPOSE 9501
The default login directory does not exist.
# We need to map our external Windows file directory to the Docker container during run
WORKDIR /mnt/d/htdocs

Copy the code

That’s our complete Dockerfile, now we’re going to generate the image file

Docker build -f php.dockerfile -t faqqcn/php-swoole-sdebug:1.0.Copy the code
  • -f means we want to use the dockerfile file
  • -t indicates a name format for our image<domain>/<name>:<tag>
  • . The final.Represents the current directory
Successfully built 9c5c20556cf2 Successfully tagged faqqcn/php-swoole-sdebug:1.0 SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build  context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files  and directories.Copy the code

The output above shows that the image was successfully created. Now take a look.

$ docker image ls                                                                                     
REPOSITORY                 TAG                         IMAGE ID            CREATED              SIZE  
faqqcn/php-swoole-sdebug   1.0                         9c5c20556cf2        About a minute ago   526MB 
Copy the code

Now let’s run it

$ docker run -di -p 8080:9501 -v D:/2vy-cc/htdocs:/mnt/d/htdocs --name php-swoole-sdebug faqqcn/php-swoole-sdebug:1.0
19db6032c9fe9cd2228844e4c029c980f14172991a4f113480ee5facd1763c2e
Copy the code
  • Parameter interpretation
parameter instructions
-di This is short for the -d and -i parameters, d for background operation and I for interactive operation
-p Enable a port mapping that maps 8080 on the host to 9501 in the container
-v Enable a directory mapping that maps the host’s D:/2vy-cc/htdocs directory to the container’s/MNT/D /htdocs
–name Give the container a name for next startup, deactivation, deletion, and logging

See the Docker run command for more parameters

And then the name of our image, and then the Docker will print out the container ID

Now go into the container.

docker exec -it php-swoole-sdebug sh
Copy the code

-it means to create an interactive operation and create a terminal, followed by the name above, and finally a startup shell. Alpine defaults to sh after entering the terminal, check PHP information and create a project

# PHP -v PHP 7.3.17 (cli) Copyright (c) 1997-2018 The PHP Group Zend Engine V3.3.17, Copyright (c) 1998-2018 Zend Technologies with Sdebug V2.7.3-dev, Copyright (c) 2002-2019, by Derick Rethans # php [PHP Modules] Core ctype curl date dom fileinfo filter ftp gd hash iconv json libxml mbstring mysqli mysqlnd openssl pcntl pcre PDO pdo_mysql pdo_sqlite Phar posix readline redis Reflection sdebug session SimpleXML  sockets sodium SPL sqlite3 standard swoole tokenizer xml xmlreader xmlwriter zlib [Zend Modules] Sdebug # composer ... / ____ _____ _____ _____ _____ _____ _____ _____ / / / / / (` __ \ / __ / __ \ / ___ / _ \ / ___ / / / ___ / / __ / / / / / / / / _ / / / _ (__) __ / / there comes \ \ _____ / _ _ /. / / / _ ___ / / ____ ____ / / ___ / __ / / _ / Composer version 1.10.5 2020-04-10 11:44:22Copy the code

You can see that swoole, Redis, Sdebug, Composer are installed, and next we will create a Hyperf project

Create a project

# composer create-project hyperf/hyperf-skeleton
Copy the code

There will be a boot during the installation, where you can either press Enter by default or select your own components as needed. Now enter the project and start it.

cd hyperf-skeleton
php bin/hyperf.php start
Copy the code

You will see all the errors pop up, but don’t worry, if you look closely, you will see that this is a Redis error, we will fix it later. For the sake of our pleasant development, if we have to execute the above command every time we modify the file, we will now install a tool to automatically restart the file after modification.

# curl -o watch https://gitee.com/liangguifeng/hyperf-watch/raw/master/watch

# ls -alF | grep watch
  -rwxr-xr-x    1 root     root          3921 May  4 07:40 watch*

Copy the code

If there’s no x in the watch permission here, let’s add it manually

chmod +x watch
Copy the code

Now let’s execute PHP Watch. Then open PHPStorm in the host, start writing code in PHPStorm, and configure Sdebug.

PHPStorm

Open the file

  • Config /autoload/async_queue.php'processes' => 1,'processes' => 0,Note, here refers to turn off the asynchronous queue, and thus to solve the Redis error in the console, if you need to use the asynchronous queue, please bring here remains the same, and to the config/autoload/Redis. The PHP configuration Redis link information correctly.

We have mapped 8080 on the host to port 9501 on the host, so we will directly access port 8080 on the host.

OK, now that we have access to the project deployed in Docker, configure debugging. Open the PHPStorm set into the Languages & Frameworks | PHP, looks like this.

Click here…

Select + and select From Docker…

If successful is not successful, you did not enable TCP connections in the first step

Select mirror image here.

Ok after checking and confirming

Now go in here and re-select the container and the native mapping relationship to help us find the corresponding file during debugging, otherwise debugging will fail.

Delete an existing mapping and select the default mapping

Then click “Mapping” on the previous line to add

Now add the directory mapping

Now, in the open Languages and Frameworks is set | | PHP Debug

Create a service and fill in the corresponding information, remembering the Name XDEBUG_02

Create a new debug

Adding a Configuration

Now click on the phone in the upper right corner to change it to this state.

Start debugging!

Switch to the container window, terminate the previous command, now we run PHP watch, you will find that it is stuck!! What the hell is this? This means Xdebug is working and if you go to PHPStorm, you’ll notice that the skip button on the left is green and the breakpoint button is green. Now if we go from the new point to the Debugger column, you’ll notice that there is an error. And there are no effects in the IDE. Because it’s not really done yet.

Now let’s fix it. According to the error message, we can simply learn that it is necessary to use the environment variable called PHP_IDE_CONFIG, and click more info… Go to the PHPStorm documentation page, search PHP_IDE_CONFIG, and find that we need to configure a parameter called serverName, which is the Server created earlier, to map local files.

Since we are debugging the CLI inside the container, we go to the terminal of the container and type the following

export PHP_IDE_CONFIG=serverName=XDEBUG_02
Copy the code

Then execute PHP Watch. Now you’ll see, when we’re on watch, the break point starts working.

Now if you debug, you will notice that the following debug bar sometimes has several hyperf.php cuts back and forth, which is very disturbing. This is because the project is configured to use multiple workers by default. You can change it to 1 here.

Business debugging

Now try debugging your business code! Go to the default controller, next breakpoint.

Open the browser refresh and you will see that nothing has changed and that the breakpoint has not been caught.

You just add XDEBUG_SESSION_START=PHPSTORM to the URl and the URl becomes http://localhost:8080/? XDEBUG_SESSION_START=233 Now we can see that PHPStorm has successfully loaded the breakpoint.

If this is too much trouble, you can install a Chrome extension called Xdebuge Helper. After installation, right-click on the plugin bar and select options, select PHPSTORM in the IDE Key and save, return to the page, left-click on the bug in the plugin bar and select Debug. Now refresh the page and PHPSTORM will automatically capture Debug.

Debug in POSTMAN

We can debug GET requests directly in the browser, but sometimes when we need to send headers or posts, we will use tools like POSTMAN to request. In this case, we just need to add XDEBUG_SESSION_START=PHPSTORM to the request parameter. We can also add XDEBUG_SESSION=PHPSTORM to the Cookie to trigger debugging.

The end.

The whole thing is a bit more complicated than the previous article, but I’ve tried to say as much as I can with as little as possible.

If you have other ideas or good suggestions can contact me directly, if you find the content of the article is wrong, welcome to point out.

If you’re still interested in remote debugging, check out my other article on XDEBUG remote debugging. Xdebug remote debugging, can you use it?

Refer to the content

  • Networking features in Docker Desktop for Windows | Docker Documentation
  • Debug a PHP CLI script – Help | PhpStorm
  • hyperf-watch
  • Install – Hyperf
  • Mabu233 / sDEBUG: Xdebug – Step Debugger and Debugging Aid for PHP