Phpactor 2022.10.11

Today I have tagged version 2022.10.11.

This is the first (and hopefully not the last) monthly release, the full changelog is on the release page. I’ll run through some of the highlights in this post.

Generate Decorator

Thanks to the perserverance mamazu there is now a code action to generate a decorator:

Generate Decorator

This is an LSP only action, and must be invoked in a file with an empty class which implements one or more interfaces.

I’m really happy to see this, I don’t use decorators often, but when I do I always think “this should be automated”. Now it is 🎉

Goto Interface Definition of Method Declaration

This is a very minor feature, but also surprisingly useful. Before the ticket was raised I hadn’t really considered it.

Given you on method in a class which is implementing an interface (<> below):

interface Foo {
    public function bar(): void; // will jump here
}

class FooImplementation implements Foo {
   public function b<>ar(): void
   {
   }
}

You can now jump to the signature in the interface by invoking “Goto Definition” on the signature in the implementation (bar in the case above). The inverse operation is the existing “Goto Implementations” action.

Class String Template and Better Generics

The code for generics has been improved significantly, and while there are still some features to come (e.g. injecting template vars through the constructor) these features will now be much easier to implement.

This release:

  • Fixes the behavior of iterable generics when multiple levels of inheritance are used (#1875)
  • Supports the use of method-level template vars. (e.g. @param T and @return T)
  • Supports the use of class-string<T>

The last feature is quite exciting:

class-string template param

Given the following class:

class Container {
    /**
     * @tempalte T
     * @param class-string<T> $fqn
     * @return T
     */
    public function get(string $fqn): object
}

When you call $foobar = $container->get(Foobar::class) Phpactor will be able to infer that $foobar is an object of type Foobar.

A wild usage can be seen in the valinor library, something like:

likevalinor Like Valinor

Dedicated Stubs

Previously Phpactor used PHPStorm stubs exclusively (by default at least) - that was until I realised that a bug with enums was caused by this library - namely that the interface BackedEnum has a property. The parser wasn’t happy about that and subsequently enums had no method completion.

Phpactor now has a few “dedicated” stubs. This allows us to fix the enum “issue” above, and also, mainly for testing purposes, be able to depend on fundamental stubs like Iterable, ArrayAccess, IteratorAggregate, etc.

Summary

There are more bug fixes and improvements listed in the changelog, including a significant performance improvement for large documents.

I know that performance is still an issue, especially with very large and complicated source files. I’ve been thinking about ways to improve it. One possible way would be to distribute the language server work over multiple processes (e.g. diagnostics, completion, code actions, etc), which would allow the use of multiple cores. This isn’t trivial however and adds more complexity.

Another option is investing more time into untangling WorseReflection which I suspect to be highly inefficient, if it’s not highly inefficient then it could at least be made to be more efficient, or at least, intelligible.

Next month should see the final pieces of the generics puzzle fall into place.