-
-
Notifications
You must be signed in to change notification settings - Fork 154
Orphaned language-server:diagnostics Process When File Contains namespace Timer #2913
Copy link
Copy link
Closed
Labels
Description
Describe the bug
When a PHP file contains the line namespace Timer;, Phpactor spawns a language-server:diagnostics process that becomes orphaned and does not terminate as expected. This issue does not occur with other namespace names.
Environment
$ php -v
PHP 8.4.10 (cli) (built: Jul 4 2025 12:41:44) (NTS)
Copyright (c) The PHP Group
$ phpactor -V
Phpactor 2025.04.17.0
To Reproduce
-
Create a directory (e.g.,
lsp-test). -
Add two files:
code.php— contains the PHP code that triggers the issue.lsp-test.php— a script that simulates an LSP client to reproduce the problem.
Directory structure:
lsp-test/ ├── code.php └── lsp-test.phpcode.php
<?php namespace Timer;
lsp-test.php
<?php function sendLspMessage($pipes, $message) { $lspMessage = "Content-Length: " . strlen($message) . "\r\n\r\n" . $message; echo "------------------\n"; // Debugging output echo ">>>\n$lspMessage\n"; // Debugging output fwrite($pipes[0], $lspMessage); fflush($pipes[0]); // Read response $response = ''; while (!feof($pipes[1])) { $line = fgets($pipes[1]); if ($line === FALSE) { break; } $response .= $line; if (strpos($response, "\r\n\r\n") !== FALSE) { // Read the JSON content based on Content-Length if (preg_match('/Content-Length: (\d+)/', $response, $matches)) { $contentLength = (int)$matches[1]; $jsonStart = strpos($response, "\r\n\r\n") + 4; $currentJsonLength = strlen($response) - $jsonStart; while ($currentJsonLength < $contentLength) { $chunk = fread($pipes[1], $contentLength - $currentJsonLength); $response .= $chunk; $currentJsonLength = strlen($response) - $jsonStart; } break; } } } echo "<<<\n$response\n"; // Debugging output echo "------------------\n"; // Debugging output" return $response; } function initializeLsp($pipes, $rootPath) { $initRequest = [ 'jsonrpc' => '2.0', 'id' => 1, 'method' => 'initialize', 'params' => [ 'processId' => getmypid(), 'rootUri' => 'file://' . realpath($rootPath), 'capabilities' => [ 'textDocument' => [ 'synchronization' => [ 'didOpen' => TRUE, 'didChange' => TRUE, 'didClose' => TRUE, ], ], ], ], ]; $jsonRequest = json_encode($initRequest); return sendLspMessage($pipes, $jsonRequest); } function openDocument($pipes, $filePath) { $lspRequest = [ 'jsonrpc' => '2.0', 'method' => 'textDocument/didOpen', 'params' => [ 'textDocument' => [ 'uri' => 'file://' . realpath($filePath), 'languageId' => 'php', 'version' => 1, 'text' => file_get_contents($filePath), ], ], ]; $jsonRequest = json_encode($lspRequest); return sendLspMessage($pipes, $jsonRequest); } function shutdownLsp($pipes) { $shutdownRequest = [ 'jsonrpc' => '2.0', 'id' => 2, 'method' => 'shutdown', 'params' => NULL, ]; $jsonRequest = json_encode($shutdownRequest); return sendLspMessage($pipes, $jsonRequest); } function exitLsp($pipes) { $exitNotification = [ 'jsonrpc' => '2.0', 'method' => 'exit', 'params' => NULL, ]; $jsonRequest = json_encode($exitNotification); return sendLspMessage($pipes, $jsonRequest); } // ---------------------------------------------------- // Launch phpactor language server using proc_open $descriptorspec = [ 0 => ['pipe', 'r'], // stdin 1 => ['pipe', 'w'], // stdout 2 => ['pipe', 'w'], // stderr ]; $lspCmd = 'phpactor language-server'; echo "!!! Starting phpactor language server by command: {$lspCmd}\n"; $process = proc_open($lspCmd, $descriptorspec, $pipes); if (!is_resource($process)) { echo "Failed to start phpactor language server, please change the command or check your installation.\n"; exit(1); } // Initialize LSP initializeLsp($pipes, __DIR__); echo "!!! Initialize completed\n"; // Send initialized notification $initializedNotification = json_encode( [ 'jsonrpc' => '2.0', 'method' => 'initialized', 'params' => [], ] ); sendLspMessage($pipes, $initializedNotification); echo "!!! Initialized notification sent\n"; // Open document openDocument($pipes, __DIR__ . '/code.php'); echo "!!! Document opened\n"; // Wait for a while to ensure the server is ready and processing the document sleep(10); // Shutdown LSP server gracefully shutdownLsp($pipes); echo "!!! Shutdown request sent\n"; // Send exit notification exitLsp($pipes); echo "!!! Exit notification sent\n"; // Close pipes and process fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process);
-
Run
php lsp-test.phpto simulate an LSP client and trigger the issue.Demo
phpactor.mp4
Reactions are currently unavailable