Skip to content

Conversation

jakubmisek
Copy link
Contributor

@jakubmisek jakubmisek commented Jun 6, 2025

This pull request adds support for devsense-php-ls, the language server used by the PHP Tools extension for Visual Studio Code.

This language server offers a comprehensive PHP development experience (within the limits of the LSP protocol), including:

  • Laravel IDE features
  • Support for PhpStan, Psalm, and other PHPDoc annotations
  • Code completion
  • Inlay hints
  • Code diagnostics
  • Code navigation
  • Code folding
  • And more

Configuration

Once the extension is installed, the language server can be enabled via settings. A separate PR will be submitted to update https://github.com/zed-industries/zed/blob/main/docs/src/languages/php.md after this PR is merged.

"languages": {
  "PHP": {
    "language_servers": ["phptools", "!intelephense", "!phpactor", "..."]
  }
}

Next Steps

After this is merged, I plan to:

  • Add more PHP-specific features
  • Document the freemium licensing model
  • Reference the extension on our website
  • Promote it via social media

This comment was marked as resolved.

@jakubmisek

This comment was marked as resolved.

@cla-bot cla-bot bot added the cla-signed label Jun 6, 2025

This comment was marked as resolved.

@notpeter
Copy link
Contributor

notpeter commented Jun 6, 2025

Exciting! I was not familiar with the phptools LSP, but I would love for Zed to support it! I'm not sure want to immediately ship with it as the default, both because it's untested, but also because we prefer to not auto-download proprietary binaries by default.

That said, I know user's experience with phpactor has not been amazing and I would love to improve the experience for coding PHP in Zed. Looking forward to testing it out.

@notpeter notpeter changed the title Add Support for devsense-php-ls Language Server Add devsense-php-ls LSP support Jun 6, 2025
@jakubmisek
Copy link
Contributor Author

Thank you @notpeter - we're excited to have our LSP in Zed. It surely needs to be tested first, and we're keen to improve or update features to fit in Zed's user experience.

Some features need to be implemented outside the LS in Rust code - but that's for another PR. (for example the activation can be added as a Zed command).

@ADmad
Copy link

ADmad commented Jun 7, 2025

That said, I know user's experience with phpactor has not been amazing

Seeing the "Resolving code actions" flash in the status bar, every time you move the cursor, itself is pretty annoying 🙂

@rabol
Copy link

rabol commented Jun 12, 2025

cannot wait to see this merged!

@jakubmisek
Copy link
Contributor Author

jakubmisek commented Jun 13, 2025

Note: the binary ./bin/devsense-php.ls needs to be chmod'ed +x
This will be fixed in the next update of https://www.npmjs.com/package/devsense-php-ls

Thanks @rabol for quick testing!

@notpeter notpeter requested a review from osiewicz July 14, 2025 16:53
Copy link
Contributor

@osiewicz osiewicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of nits, but other than that, LGTM

@osiewicz osiewicz merged commit b45e080 into zed-extensions:main Jul 15, 2025
1 check passed
@osiewicz
Copy link
Contributor

Thanks! I'll cut a new extension version shortly.

@jakubmisek
Copy link
Contributor Author

Thank you @osiewicz - we're looking forward to it!

@matheus-de-araujo
Copy link

I'm already using it with my premium license — it's amazing!

I configured the license by adding an environment variable in my .bashrc:

export DEVSENSE_PHP_LS_LICENSE='{...}'

Could this pose any security risks?

@jakubmisek
Copy link
Contributor Author

@matheus-de-araujo thank you for the kind words!

If the variable gets "stolen", someone else may use your premium license and/or see your name. Do you have any recommendations?

We're preparing some updates so it will be easier to activate it though.

@matheus-de-araujo
Copy link

Zed currently has no hidden or secure license storage. All plugin settings — including license keys — are stored in plain JSON in:

  • ~/.config/zed/settings.json (user/global)
  • .zed/settings.json (per-project)

In contrast, VS Code uses a secret global memento (globalState/SecretStorage) managed internally in a SQLite DB, not exposed in the user's settings

Suggested improvement:

Add a command like Zed: Enter PHP License that saves the key to a protected file (e.g., $XDG_DATA_HOME/zed/licenses.json with chmod 600) and let the LSP read it on startup — keeping the key out of visible JSON configs.

I don’t know if this would be technically feasible.

@jakubmisek
Copy link
Contributor Author

@matheus-de-araujo good idea - that's what we do in VSCode.

  • command to enter license key and store the license signature in a secure storage

@pjv
Copy link

pjv commented Jul 21, 2025

@jakubmisek any chance you could provide a little snippet showing what to add to the zed config to get phptools stubs configured?

@jakubmisek
Copy link
Contributor Author

jakubmisek commented Jul 21, 2025

@jakubmisek any chance you could provide a little snippet showing what to add to the zed config to get phptools stubs configured?

Sure, we'll prepare complete documentation soon. For now, you can drop most of the vscode-like settings into the "initialization_options":

"lsp": {
    "phptools": {
      "initialization_options": {
        "php.stubs": ["*", "zip", "zlib", "pcntl", "com", "composer", "wordpress"]
      }
    }
  }

"php.stubs" gets array of stubs where

  • "*" is a shortcut for all the standard ones
  • "all" is all the extensions (zlib, com, and ~30 more)

@pjv
Copy link

pjv commented Jul 21, 2025

@jakubmisek Thank you, it was initialization_options that I needed. I was using settings.

I wish this could be standardized for all Zed extensions.

@jakubmisek
Copy link
Contributor Author

@pjv thanks for the question - I'll take a look at "settings" as well, since it makes more sense to me personally.

@pjv
Copy link

pjv commented Jul 21, 2025

@jakubmisek sorry to keep banging away inside this PR, and let me know if i should be opening new issues somewhere else. I’m trying to configure a custom php_stubs directory and this seems not to be working for me. Can you see where I've gone wrong?

SCR-20250721-hhfz

@jakubmisek
Copy link
Contributor Author

jakubmisek commented Jul 21, 2025

@pjv it's alright here for me. You can start a new issue at https://github.com/DEVSENSE/phptools-docs/issues if you want though.

"php.workspace.includePath" should work. Do you see any error in language server Log "phptools"?

@pjv
Copy link

pjv commented Jul 21, 2025

@jakubmisek No, I don’t see any error in the logs and it tells me it’s indexing my directory:

PHP Language Server Started
Processing include path /Users/pjv/development/php_stubs ...
Indexing '/Users/pjv/development/php_stubs' ...
PID: 50387
Indexing 'file:///Users/pjv/development/projects/**/**/woo_site/custom_plugins/mm-bt-grain-coupons' ...

But when I look at some code that has, for example, calls to woocommerce classes and functions whose stubs are definitely in that directory (working correctly with the intelliphense LSP), phptools is giving me errors like this:

SCR-20250721-hlmj

@pjv
Copy link

pjv commented Jul 22, 2025

@jakubmisek is there any way i could try to track down why the extension seems not to be able to make use of the stub files that the log says it is indexing?

Do you have any easy-enough way to reproduce this issue?

FYI: If I add the stubs folder to the workspace in zed, then the unknown function warnings go away. So it seems that the problem has nothing to do with the content of the stubs files and is instead something to do with how the indexing via "php.workspace.includePath" is being parsed.

…above was incorrect; i had temporarily turned phptools off and was looking at the project with intelliphense turned on. in fact, adding the stubs project to the workspace does NOT fix the warnings.

And… LSP server logs looks like:

SCR-20250722-hsvg

@jakubmisek
Copy link
Contributor Author

@pjv got it, use the URI path format for now:

        "php.workspace.includePath": "file:///Users/pjv/development/php_stubs"

Adding the folder to the project does not work in Zed, because it treats it as another separate folder and starts a new instance of language server (this is probably be design in Zed, although it behaves differently than in VSCode)

@pjv
Copy link

pjv commented Jul 22, 2025

@jakubmisek yup, that’s working. Thank you. Looking forward to the full documentation. This is a great addition to Zed.

@kevinwombat
Copy link

kevinwombat commented Jul 30, 2025

Edit: I fixed it just after by replacing the double quotes by single quotes.

I'm already using it with my premium license — it's amazing!

I configured the license by adding an environment variable in my .bashrc:

export DEVSENSE_PHP_LS_LICENSE='{...}'

Could this pose any security risks?

Hello.
did you have to set up any other configuration. I did the same but i still get the popup saying that i need a license to use premium features.

export DEVSENSE_PHP_LS_LICENSE="{json_signature}"

And i got json_signature from https://www.devsense.com/en/purchase/validation

Thanks in advance

@jsondergaard
Copy link

jsondergaard commented Jul 30, 2025

@kevinwombat you could try adding this to your settings.json instead. I did, and it works for me, after adding backslashes to the quotes as such:

"lsp": { "phptools": { "initialization_options": { "0": "{\"name\":\"\",\"email\":\"\",\"expiration\":\"\",\"signature\":\"\"}" } } }

@jakubmisek
Copy link
Contributor Author

@kevinwombat
when setting DEVSENSE_PHP_LS_LICENSE please make sure quotes are escaped and handled correct, please check

echo $DEVSENSE_PHP_LS_LICENSE

As sugggested by @jsondergaard , settings.json is more "bulletfproof"

 "lsp": { "phptools": { "initialization_options": { "0": "{json_signature}" } } }

We'll make this process a bit simpler in a future update, I promise

@ADmad
Copy link

ADmad commented Aug 9, 2025

I assume devsense-php-ls does have support for inlay hints, correct? Yet I don't get inlay hints for parameter names. I believe I have the relevant settings enabled.

{
  "inlay_hints": {
    "enabled": true,
    "show_parameter_hints": true
  },
  "lsp": {
    "phptools": {
      "initialization_options": {
        "php.inlayHints.parameters.enabled": true
      }
    }
  }
}

@jakubmisek
Copy link
Contributor Author

jakubmisek commented Aug 9, 2025

@ADmad yes, devsense-php-ls provides inlay hints, they are enabled by default, and they don't require a license.

Let me check why they don't show up.

Edit: there was a legacy workaround for VSCode only - implemented properly and enabled for Zed and other LSP editors (devsense.-php-ls 1.0.17769). Works in Zed now:
image

@ADmad
Copy link

ADmad commented Aug 10, 2025

Thank you, I do get variable name and return type inlays now as expected 👍.

A slight issue with return type inlays though. Double clicking on the return type inlay doesn't add the return type into the code, as documented for vscode.

@jakubmisek
Copy link
Contributor Author

@ADmad not sure why InlayHint edits are not working - do they work in other languages in Zed?

@ADmad
Copy link

ADmad commented Aug 10, 2025

@jakubmisek I only work with PHP so can't say about other languages :)

@josecanciani
Copy link

I'm having problems disabling devsense. I just want to use PHP Intelephense, so I'm doing

"languages": {
  "PHP": {
    "language_servers": ["intelephense", "!phptools", "!phpactor", "..."]
  }
}

But even after restarting, I see phptool active:
image

ose@02817-jcanciani:/home/sb-01/www/iats/code$ ps -ef | grep -i devse
jose      896543  892634 99 18:48 ?        00:24:10 /home/jose/.local/share/zed/remote_extensions/work/php/node_modules/devsense-php-ls-linux-x64/dist/devsense.php.ls --composerNodes false
j

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 896543 jose      20   0  263,1g  12,5g  33048 S   0,0  81,8  24:11.14 devsense.php.ls
 

I'm using a remote SSH, not sure if that could make a difference.

Any ideas?

@jakubmisek
Copy link
Contributor Author

@josecanciani your setting is correct and Zed should even restart language server automatically upon saving the settings.json file.

You can even shorten it just one language server of your choice:

  "languages": {
    "PHP": {
      "language_servers": ["phptools"]
    }
  },

Do you see it in LSP logs "dev: open language server logs"?
image

Is the path to your setting.json correct, if you check what's happening in the zed' log ("zed: open log")?

@josecanciani
Copy link

@jakubmisek I changed it to just have intelephense, but it's still firing devsense (not phpactor though).

Logs:

2025-08-21T16:14:55-03:00 INFO  [project::environment] using project environment variables shell launched in "/Users/josecanciani/.config/zed". PATH="/Users/josecanciani/.local/bin:/Users/josecanciani/.codeium/windsurf/bin:~/bin/avature:~/bin/db:~/bin/dev:~/bin/tools:/Users/josecanciani/.local/bin:/Users/josecanciani/bin:/opt/homebrew/opt/sqlite/bin:/opt/homebrew/opt/grep/libexec/gnubin:/opt/homebrew/opt/[email protected]/sbin:/opt/homebrew/opt/[email protected]/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/X11/bin:/usr/local/go/bin:/Users/josecanciani/.local/bin:/Users/josecanciani/.codeium/windsurf/bin:~/bin/avature:~/bin/db:~/bin/dev:~/bin/tools:/Users/josecanciani/bin:/opt/homebrew/opt/sqlite/bin:/opt/homebrew/opt/grep/libexec/gnubin:/opt/homebrew/opt/[email protected]/sbin:/opt/homebrew/opt/[email protected]/bin"
2025-08-21T16:14:55-03:00 INFO  [language] fetching latest version of language server "json-language-server"
2025-08-21T16:14:57-03:00 INFO  [node_runtime] using Node.js found on PATH: SystemNodeRuntime { node: "/opt/homebrew/bin/node", npm: "/opt/homebrew/bin/npm", global_node_modules: "/opt/homebrew/lib/node_modules\n", scratch_dir: "/Users/josecanciani/Library/Application Support/Zed/node" }
2025-08-21T16:15:05-03:00 INFO  [project::prettier_store] Starting prettier at path "/Users/josecanciani/Library/Application Support/Zed/prettier"
2025-08-21T16:15:05-03:00 INFO  [lsp] starting language server process. binary path: "/opt/homebrew/bin/node", working directory: "/Users/josecanciani/Library/Application Support/Zed/prettier", args: ["/Users/josecanciani/Library/Application Support/Zed/prettier/prettier_server.js", "/Users/josecanciani/Library/Application Support/Zed/prettier"]
2025-08-21T16:15:05-03:00 INFO  [project::prettier_store] Started default prettier in "/Users/josecanciani/Library/Application Support/Zed/prettier"
2025-08-21T16:15:05-03:00 INFO  [language] language server "json-language-server" is already installed
2025-08-21T16:15:05-03:00 INFO  [lsp] starting language server process. binary path: "/opt/homebrew/bin/node", working directory: "/Users/josecanciani/.config/zed", args: ["/Users/josecanciani/Library/Application Support/Zed/languages/json-language-server/node_modules/vscode-langservers-extracted/bin/vscode-json-language-server", "--stdio"]
2025-08-21T16:15:06-03:00 ERROR [theme::settings] theme not found: Atelier Dune Light
2025-08-21T16:15:06-03:00 INFO  [project::lsp_store] Refreshing workspace configurations for servers {}
2025-08-21T16:15:06-03:00 INFO  [project::lsp_store] Refreshing workspace configurations for servers {}
2025-08-21T16:15:08-03:00 WARN  [lsp::input_handler] failed to deserialize LSP message:
{"jsonrpc":"2.0","result":{}}
2025-08-21T16:15:08-03:00 ERROR [lsp] Shutdown request failure, server prettier (id 2): Error: Unknown method: shutdown
While handling prettier request: {"jsonrpc":"2.0","id":3,"method":"shutdown","params":null}
2025-08-21T16:15:44-03:00 INFO  [project::lsp_store] Refreshing workspace configurations for servers {}
2025-08-21T16:15:44-03:00 ERROR [theme::settings] theme not found: Atelier Dune Light
2025-08-21T16:15:44-03:00 INFO  [project::lsp_store] Refreshing workspace configurations for servers {}
2025-08-21T16:15:44-03:00 INFO  [project::lsp_store] Refreshing workspace configurations for servers {}

These are the logs for phptools, which I would suppose should not be there:

image

And these for Intelephense, which is working fine:

image

BTW, Intelephense stops indexing with error "MaxUriCountError: Maximum URI count of 262143 exceeded.", not related I assume, but if you know what that could be happening, I'm glad to hear :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants