php-language-server icon indicating copy to clipboard operation
php-language-server copied to clipboard

Suggest autoloadable symbols from PHAR files

Open boenrobot opened this issue 7 years ago • 13 comments

Right now, if you have a PHP file include/require a PHAR file, the PHAR file is effectively ignored (except maybe the stub... I haven't checked that particular detail).

By design, PHAR files contain multiple files, and requiring the PHAR file itself executes the stub, which is typically used to set up an autoloader for all files of the PHAR (or more accurately, that's what typically happens for PHAR files that are meant to be included/required). Because of how typical this case is, and how useful PHAR files in general are, it would be great if the contents of PHAR files were scanned for autoloadable symbols (classes, interfaces, traits), and the stub is scanned like a normal PHP file (if it's not already scanned that way already).

boenrobot avatar Jun 16 '17 23:06 boenrobot

Could you describe what the scenario looks like? Where are these PHAR files?

felixfbecker avatar Jun 17 '17 07:06 felixfbecker

Well, I'll use one of my own libraries as an example: https://github.com/pear2/Net_RouterOS

In addition to normal distribution methods (PEAR, Composer, a zip and tgz archives), it is also distributed as a PHAR file that includes all dependencies and an autoloader to load all the classes (see "releases"). To use it, you just place it anywhere on the file system, and include/require it like any PHP file.

When you include/require the PHAR file, the stub does a Phar::mapPhar() call to enable files from it to be loaded, and registers itself with an autoloader (in this case PEAR2_Autoload) to actually do the loading. Thus, you can use any autoloadable symbols (in this case, just classes) from inside the PHAR file as part of your larger application.

That particular PHAR file is also executable (i.e. when you are running it directly from the command line, it has a different effect that the stub accounts for), but as far as an IDE is concerned, that part is not something to worry about.

Technically, it's possible for a PHAR file to NOT enable all or any of its symbols be loaded (instead, just execute its stub...). However, there's no way to know that with static analysis alone, so IMHO, it's a fair game to just include all autoloadable symbols in the suggestions.

boenrobot avatar Jun 17 '17 12:06 boenrobot

Well, if you need to require it and it's not inside the workspace, it would need #379 first. Otherwise I assume it is nothing but reading files from the archive, but not sure how that would work over LSP (files extension). Also j2d to a file inside the archive is probably not possible since no editor would be able to look inside it.

felixfbecker avatar Jun 17 '17 13:06 felixfbecker

Well, if you need to require it and it's not inside the workspace, it would need #379 first.

Completely acceptable caveat IMHO.

Otherwise I assume it is nothing but reading files from the archive, but not sure how that would work over LSP (files extension).

The PHAR file could be extracted in a "cache" folder (cache key based on an encoded/hashed path), and watched for modifications to keep the cache in sync. Then the suggestions would be based on reading the extracted contents, rather than the PHAR itself.

(At least that appears to be the approach of IDEs that support this feature)

Also j2d to a file inside the archive is probably not possible since no editor would be able to look inside it.

You mean showing the contents in VSC as if the PHAR file was a folder? That sounds like a separate feature, perhaps one for a separate VSC extension even.

boenrobot avatar Jun 17 '17 13:06 boenrobot

I still don't see a way to make this work when running the language server in an isolated container where it can only get text document contents through LSP. Anything you extract into a temporary folder would not be available to the client, besides that there is currently no way to fetch binary content.

felixfbecker avatar Jun 17 '17 13:06 felixfbecker

Anything you extract into a temporary folder would not be available to the client,

But it doesn't need to be, does it? I mean, I'm not familiar with LSP, but isn't it supposed to be basically that you get the text with some IDE meta data, and are supposed to respond with a list of suggestions for the IDE (or whatever the request asks you to respond with)?

In other words, as long as the server can formulate the suggestions (i.e. as long as it can access and parse the files), the client doesn't need to know that these suggestions were formulated based on contents of files that it can't access.

besides that there is currently no way to fetch binary content.

As long as you know the path to the PHAR (which LSP should deliver as part of the full text, right?), you can process it with PHP's Phar class, which can open it based on the path alone.

boenrobot avatar Jun 17 '17 13:06 boenrobot

i.e. as long as it can access and parse the files

that's exactly the problem I described when the language server is running on a different host than the client

felixfbecker avatar Jun 17 '17 13:06 felixfbecker

Ah. I see. That doesn't sound like a typical case to me, but I guess it's possible, so it's fair to support it.

So yeah, the client would need to somehow send the contents of the PHAR... And there's no way for the VSC extension to make LSP do that? Can't the VSC extension claim to "handle" PHAR files, and thus have VSC send such contents separately? Or... wait, no... that would require the user to actually open the PHAR file in their editor, right? Nevermind...

boenrobot avatar Jun 17 '17 14:06 boenrobot

It actually is - think about Eclipse Che and sourcegraph.com.

It would require an extension of the protocol.

Do you have any data on how many people use PHAR releases vs Composer?

felixfbecker avatar Jun 17 '17 14:06 felixfbecker

I don't have complete numbers, and I can only speak for my libraries, but... any library that I have published a PHAR release of is used more often in that way than over Composer (or at least, I'm more often contacted to assist people who use it that way). The download numbers are a bit more in favor of Composer, but I believe this is just due to people clearing their vendor folder, not because of users being larger in number.

PHP newbies like the ease of PHAR - you just include it, and it works.

For seasoned developers, installing and using Composer is not a big hurdle, so that's their preferred method.

Now... I realize that using PHAR files as libraries isn't exactly the most wide spread of a practice, precisely because of the rift between PHP newbies and PHP veterans. PHP veterans treat PHAR as a format for self contained binaries ala composer.phar, phpDocumentor.phar, phpunit.phar, etc. and PHP newbies often copy&paste smaller code fragments and PHP files, rather than using PHAR libraries (or Composer). My libraries, and the small number of other libraries released as PHAR files exist in a niche where they try to serve all sides, which is no easy feat, and thus not something that's typically done by library developers.

boenrobot avatar Jun 17 '17 14:06 boenrobot

I dont know any lib which is distributed as a phar. Only usages of phar I am aware of are executable cli tools

staabm avatar Jun 17 '17 16:06 staabm

@staabm Right... That's the most common use. Like I said, seasoned developers tend to use Composer for libraries, since it allows them to manage incompatibilities between different libraries easier, and it's easier to do a "dirty patch" on an extracted file than modify a PHAR file.

Here's some libraries that (unlike the previous example of a library of my own) I had nothing to do with, and have PHAR distributions: https://documentation.antavo.com/developer-documentation/antavo-sdks/php-sdk/ https://maxmind.github.io/GeoIP2-php/ https://tokbox.com/developer/sdks/php/ http://devbay.net/sdk/guides/getting-started/installation.html https://docs.bugsnag.com/platforms/php/other/ http://phphttpclient.com/

Sure, all of them also support Composer (as do I), but the point is that using them as a library from a PHAR file is a legit use case for them as well.

boenrobot avatar Jun 17 '17 17:06 boenrobot

One most common case where you really depend on the ability to parse PHAR-files for symbols is when you're trying to write plugins for Composer.

Today I've been trying to understand the way silverstripe's vendor-plugin is working but most classes, such as Composer\IO\IOInterface, Composer\Util\Filesystem and Composer\Util\Platform are located in the composer.phar-file.

https://github.com/silverstripe/vendor-plugin/blob/master/src/VendorExposeTask.php#L62-L99

Are you sure there's no way to convert the text-flavored data sent by LSP back into its binary form?

manuth avatar Oct 09 '19 13:10 manuth