Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support XDebug step debugging #70

Open
marc-mabe opened this issue Oct 4, 2021 · 0 comments
Open

Support XDebug step debugging #70

marc-mabe opened this issue Oct 4, 2021 · 0 comments
Labels
Enhancement New feature or request

Comments

@marc-mabe
Copy link

marc-mabe commented Oct 4, 2021

Feature Request

Q A
New Feature yes
RFC no
BC Break no

Summary

Debugging swoole applications is much harder as 1. XDebug step debugging does not work out-of-the box and 2. because printing debug messages get send into nirvana.

Both are not related a mezzio swoole but to the nature how the swoole webserver works.

I think I found a good way to support xdebug step debugging requests by manually reproducing what xdebug does normally to start a debug session on http request and would like to get your thoughts about this.

PS: Currently this is a prov-of-concept for step debugging only but it should also be possible for profiling and other debugging sessions.

Requirements to make it work:

  • xdebug installed and debug mode enabled
  • coroutines turned off (Actually didn't test with coroutines turned on yet)
  • Add XDebugSessionRequestListener as first RequestEvent listener ín development.config.php
class XDebugSessionRequestListener
{
    private bool $isAvailable = false;

    private string $startWithRequest = 'trigger';

    private string $triggerValue = '';

    public function __construct()
    {
        if (!\extension_loaded('xdebug')) {
            return;
        }

        $mode = (string)(\getenv('XDEBUG_MODE') ?: \ini_get('xdebug.mode') ?? '');
        if (!\in_array('debug', \explode(',', $mode), true)) {
            return;
        }

        // env XDEBUG_CONFIG
        $envConfig        = [];
        $envConfigEntries = \explode(' ', (string)\getenv('XDEBUG_CONFIG'));
        foreach ($envConfigEntries as $envConfigEntry) {
            $envConfigSplit                = \explode('=', $envConfigEntry);
            $envConfig[$envConfigSplit[0]] = $envConfigSplit[1] ?? null;
        }

        $startWithRequest = $envConfig['start_with_request'] ?? (string)\ini_get('xdebug.start_with_request');
        if ($startWithRequest === 'no') {
            return;
        }

        // Normalize "xdebug.start_with_request" setting
        // as the value "default" depends on "xdebug.mode":
        //    debug: trigger
        //    gcstats: no
        //    profile: yes
        //    trace: trigger
        // -> We already expect "xdebug.mode" to include "debug"
        if ($startWithRequest === 'default') {
            $startWithRequest = 'trigger';
        }

        $this->startWithRequest = $startWithRequest;
        $this->triggerValue     = $envConfig['trigger_value'] ?? (string)\ini_get('xdebug.trigger_value');
        $this->isAvailable      = true;
    }

    public function __invoke(RequestEvent $event): void
    {
        if (!$this->isAvailable) {
            return;
        }

        // XDebug is configured to auto start on each request
        if ($this->startWithRequest === 'yes') {
            $this->start();
            return;
        }

        if ($this->startWithRequest !== 'trigger') {
            return;
        }

        $request = $event->getRequest();

        $requestValue = $request->cookie['XDEBUG_TRIGGER']
            ?? $request->get['XDEBUG_TRIGGER']
            ?? $request->post['XDEBUG_TRIGGER']
            ?? null;

        // legacy triggers
        $requestValue ??= $request->cookie['XDEBUG_SESSION']
            ?? $request->get['XDEBUG_SESSION']
            ?? $request->post['XDEBUG_SESSION']
            ?? null;

        if ($requestValue === $this->triggerValue || ($requestValue !== null && !$this->triggerValue)) {
            $this->start();
        }
    }

    private function start(): void
    {
        if (\function_exists('xdebug_connect_to_client')) {
            // XDebug >= 3.1
            \xdebug_connect_to_client();
        } else {
            // XDebug < 3.1 we have to set a breakpoint
            \xdebug_break();
        }
    }
}
@marc-mabe marc-mabe added the Enhancement New feature or request label Oct 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant