It has been a significant 8 months for Phpactor:
- Conversion to a mono-repository.
- Completely refactored type system.
- Phpactor theme song.
- Numerous features and improvements (see highlights)
Converting Phpactor to a monorepo has accelerated development significantly, it has been far easier to fix bugs and add features. It is imaginable to say that more progress has been made in these 8 months than in the past 3 years and it’s still awful.
I’ve decided to use
tagging releases as
YYYY.MM.DD) from now
on. Previously Phpactor has been stuck in the long hell of
which begs the question: what would
1.0.0 look like? Semantic versioning
doesn’t make any sense here, Phpactor is not a library, and since it is now a
monorepo, it also does not offer extension points which plugins would depend
on, and if it did, the API can be offered as a separate, semantically versioned,
Tagging Phpactor is, for me, a symbolic act - development is continouous. Some people were still using the
0.18version. From now on I’ll try and tag a new version each month for the benefit of the changelog, people that require tagged versions and to give me something to blog about.
Removal of the extension manager ¶
I made a big thing of Phpactor Extensions. The dream was you could start with only the extension manager package, and build your own Phpactor. In practice I created a monster that was tightly coupled to the internals of Composer 1.
As Composer 1 became more deprecated I was faced with the looming spectre of having to rewrite the extension manager from scratch. I didn’t have the time. In addition, having the monorepo meant that extensions would have to depend on the entire monorepo package for testing (no I have not yet, and probably never will, setup a repo split).
Finally I opted to simply remove the extension manager and bundle the extensions into Phpactor by default, they are just “available” to be activated with a config switch.
This decreases the maintainence burden by assuring that they always work, on other hand it increases it by requiring community initiatives to be merged into the monorepo, but so far this hasn’t been a huge issue.
Some highlights from the changelog:
- Completely new type system
- Better constant support - indexing, goto def, find references, hover, etc.
- Lazily resolve documentation for completion items
- Generate constructor refactoring
- Fill object refactoring
- Remove unused imports diagnositcs and code transformation
- Added native WR single-pass diagnostics #1700
- Index clean command #1691 @mamazu
- Support for mixins
- Docblock completion
- Support for type assertions via.
- Array shape type support (types and basic completion)
- Support for variadics
- Send rename file request to client when renaming a PSR class @przepompownia
- Generics mostly supported
- PHPStan, Psalm and (experimental) Behat extensions are now included by default.
- Enum support (requires 8.1 PHP runtime)
- Many more things I didn’t even add to the changelog!
Type System and Flow ¶
Refactoring the Phpactor type system was the main motiviation for the change to the monorepo as it is something that affects many of the previous satellite packages (of which there were some 50 or so).
The new system gives it some level of parity with the Phpstan and Psalm type systems while the flow analysis is much better than it was, but still lacking when compared to the static analysers.
VS Code ¶
Many VSCode specific bugs have been fixed.
Phpactor now has a “single pass” diagnostics engine which is easily
extensible, for development purposes Phpactor now also provides
phpactor analyse which works just like PHPStan or Psalm:
As it only has about 4 “rules” and is about 4x slower than your favourite SA tool I would not recommend using it for that purpose. The engine does however provide a good way to highlight when a code action can be applied, e.g. remove missing imports:
Marcel Pociot reached out to me to let me know that Tinkerwell uses Phpactor under the hood (albeit a modified fork), and has provided sponsorship of €100 a month for which I’m very grateful 💗 (and also to my other sponsors).
Working on a language server is an incredibly time consuming hobby, especially when it’s as badly written as Phpactor is, maybe one day I can get enough sponsorship to write it properly.
In addition I registered a Blackfire open source license to help improve Phpactor’s performance.
The monorepository has made the project far easier to contribute to, but lots
of the code is, I fear, difficult to understand and lacks some unifying
principles (although progress has been made). The self-inflicted maintainence
burden is still quite high, it’s still the case that a “quick” improvement can
quickly expand into 4 or more hours of my day, and some “bugs” resurface again
and again (looking at you,
UnusedImportProvider). Saying that, it’s also the
case that I’ve fixed 3 bugs in the hour before starting work, so it’s not all
I increasingly feel that I am actively writing (tolerably well tested) legacy code, and perhaps more time needs to be spent on refactoring the code base.
One such refactoring would be to create a Intermediate Representation on top of the AST. Such a thing could be seen as a DOM document for code, and following in the footsteps of frontend libraries such as React (I think, I’m not a frontend person) it could be updated incrementally and not rebuilt from scratch all the time.
Nodes in the IR would be augmented with type information and the IR would also include Docblock nodes.
Ultimately it could mean:
- Vastly improved performance for diagnostics, completion and just about anything else that depends on static analysis.
- (theoretically) lossless abstraction (no more re-parsing/re-traversing the raw AST)
- Can analyse Docblock and PHP nodes with the same API
I kind of imagine the document being broken down into blocks which are
defined by scope (e.g. an
if branch is a “block”) and atomic text edits
would affect a single block, which may in turn have children which depend on
it and are affected by the change, or not. But much more thought needs to be
applied to this crazy theory.