CakePHP Static Analyzer updates

You might remember my blog post from beginning of this year.
In this article I want to give a quick feedback on what happened so far.

CakeDC PHPStan extension

The authors of CakeDC/cakephp-phpstan did a great job over the last months getting the support of CakePHP for PHPStan/Psalm to a new level.
It now even supports trait methods like fetchTable() as well as sanity detectors for components and mailers (if they exist and are valid).
This is definitely a must-have in your app dev as it avoids quite a few bugs as well as alerts you early on refactoring.

It also supports some upgradability help with old array to property syntax for entities:

  • DisallowEntityArrayAccessRule: This rule disallow array access to entity in favor of object notation, making it easier to detect a wrong property and to refactor code.

Check out all the rules here: readme-ov-file#rules

IdeHelper

The probably by far most important CakePHP plugin for local development has been further improved.
Running IdeHelper regularly and keeping your annotations up to date helps the static analyzers to properly introspect your code (and avoid false negatives).

It now (since 2.6.0) ships with wildcard support for your app plugins.
So if you have like 20 of them and you don’t want to type them out manually, you can use MyNamespace/* or even all to quickly run over them.

My composer.json now for example just has these lines:

"scripts": {
    ...
    "annotate": [
        "bin/cake annotate all",
        "bin/cake annotate all -p all"
    ],

I type composer ann, hit enter and all is done for app + all app plugins.

Composer shortcut

Technically, since I have a shortcut at hand for composer itself, I just run c ann.
Such a shortcut you can create on your local system usually.

I use Linux, so for me this goes into ~/.bash_aliases file:

alias c='composer'

If you want to save yourself a lot of typing, this can help 🙂 Also for other commands or paths you have to type more than a few times per day.

PHPStan 2.0

PHPStan v2 came out with quite a bit of more strictness on certain elements, and also some improvements (if you didn’t use cutting edge rules, that is).
Overall it seems quite nice.
There are a few caveats and a few poorly implemented things still. But overall it is definitely worth upgrading here asap.

For apps I already did this.
I am currently blocked here in some plugins, as I have to wait for 5.1.2 to be released – see the next chapter for the reason.
One example is this.

list<> vs array<>

For me list<> was intuitively always a bit more a focused on the value of the array instead of the key.
Assoc arrays on purpose are array<KEY, value> here. Unfortunately, the PHPStan people invented this differently and in a way that is not usable for 99% of the cases. The practical use oflist` is pretty much non-existent, as it requires a pure numerically indexed array, which in reality will usually almost never be guaranteed.
So kind of sad to not have a practically usable list type here.

With CakePHP 5.1.2 (in ~2 weeks) there will be a revert on the list<> type annotations in favor of simple array<> ones for @param.
This is covariant with your possibly stricter app/plugin code and thus safe to apply in a patch.
CakePHP 5.2.0 will completely revert all list<> type annotations to array<>, so also for return type or property type ones.
This will require some app/plugin adjustments and will be documented as such.

Best to make sure your code already uses list<> only where you can absolutely say for sure this is the case, e.g. when defining a constant or (read-only) attribute.
In most following code, reading by key or adding by key will definitely break this. Also even just iterating over it and using the key in any reading way.

array<value-type> vs array<key-key, type>

With the above facts the basic recommendation still stands: always annotate your iterable types.

The former is for pure lists then, where only the value matters and we usually don’t directly read or write by key.
At least for reading usually you iterate over the values.

The latter is for associative arrays, often times config arrays.
You can also nest them, e.g. a 2-level nested one could look like array<string, array<string, mixed>>.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.