Looking at the forum FAQ it looks like linking to your own article is okay if itās relevant to the community, so here goes. Iāll try to summarize the article here so busy readers donāt have to click through!
Kirby 3 is using PHP 7ās type annotations extensively in its source code, but oftentimes your code editor or IDE cannot show you that information because it doesnāt know what $page or $kirby means in different contexts, like templates and controllers.
I wrote an article on type hints for Kirby which explains the explains the problem ā basically, Kirby is a bit too magical for your IDEās taste ā and some solutions I found.
Type hints for templates
We can use PHPDoc syntax to declare the type of the variables injected by Kirby or by your controllers:
Now we can work with the $page variable and a good PHP IDE will offer autocompletions, parameter names and types, etc.
Type annotations for controllers
Since controllers are functions, we can use type annotations in the function signature:
<?php // site/controllers/article.php
use Kirby\Cms\Page;
use Kirby\Cms\Site;
return function (Page $page, Site $site) {
return [
'htmlTitle' => $page->title() . ' ā ' . $site->title()
];
}
Okay but whatās a good code editor for this?
Iāve mostly used PhpStorm, which is great but not cheap. Other IDEs like Netbeans or Visual Studio might work well too.
VS Code doesnāt have much PHP support out of the box, but I tried the PHP Intelephense extension and it seems to work well (make sure to follow the āQuick Startā steps).
I just tried this for Visual Code v1.71.2 and PHP Intelephense v1.8.2 with PHP8. It can resolve some Kirby 3.7 helpers but variables like $page are not resolved in my controllers or templates within the PHP open/end tags. Is there nowadays a way to get this to work without adding Type hints or Type Annotations by hand in your custom code? If I do that, resolving the variable works but of course it adds additional, repetetive work. Would it help to have a PHP Intelephense license for the full feature set?
Thank you for your thread and thanks to everyone who helps!
And tools like Intelephense or PHPStorm might be clever enough to see that and apply those definitions in all files.
But Kirby does not declare those variables as globals. Instead, it provides those variables in templates, or provides them to specific functions (like controllers). If you lie to your type intelligence system by saying theyāre globals, youāll probably end up writing bugs (like trying to use $kirby in a config file).
Something that can help is using Kirbyās helper functions, which are available in templates and other contexts:
Instead of $page, use page()
Instead of $site, use site()
Instead of $kirby, use kirby()
In my experience, Intelephense and PhpStorm both recognize those functions and understand their return types, so you get the same benefit as declaring the type of $page, $site and $kirby, but in a less verbose way.
Personally I still use the /** @var */ declarations in templates, mostly because I have custom models for every template, and page() only gives me the parent Kirby\Cms\Page class, not my subclass. So I do stuff like:
Sorry for not properly reading your original post - and thank you for the detailed answer. Learnt something again today and it might be of value for those, who find this thread
Hey, sorry for digging up this old post. Iāve read your post and the comments, and done some other research unsuccessfully. I want to show Kirby to some of my coworkers that only use PHPStorm. I canāt seem to get good type hints to work in the snippets + templates files.
Adding these declarations at the start of the files helps a bit:
Iāve done some reading and googling but cannot seem to figure out how to get PHPStorm to stop struggling with kirby in these two folders. I previously only used VSCode with PHP Intellisense and never encountered this problem. Anybody got some tips?
You can avoid the issues with the field methods if you make a habit of replacing the magic calls title, myFieldName etc., with the longer version `$page->content()->get(ātitleā)->esc(). And then use @lukaskleinschmidtās plugin to take care of some other issues. Itās partly a problem with these magic methods and partly a problem with methods hidden away in arrays/aliases, and other problems with missing type hinting in the core.
We are working on improving type hinting in the core, donāt know if that will fix all issues in the future, but it will definitely get better.
Yeah I think the main issues with type hints in Kirby are:
Method overloading, especially for content fields. This can be bypassed by using $page->content()->get('field_name') instead of $page->field_name().
Registering new methods for blocks, pages, etc. in plugins (see block methods, page methods), since those get added to some registries dynamically and no static analysis tool can discover them (unless itās specifically written for Kirby plugins). No workarounds here Iām afraid.
Controllers can inject random data that static analysis will not know about. Workaround: declare those variables with /** @var */ in the template (but thatās duplicating information and can get out-of-sync with changes in the controller).
Collections can return arbitrary data that static analysis doesnāt know about.
etc.
Iām working on a Rails site these days, and Iām basically having the same issues due to all the auto-loading and convention-over-configuration approach which makes code very hard to figure out for static analysis tools (and Iād argue, also for lowly humans such as myself).
When it comes to Kirby, on the last project I did, I tried to use methods of code organization and code reuse that can be typed:
Using page models, instead of registering page methods.
Only use controllers for HTTP stuff (e.g. redirecting or returning an error), not to prepare data that will be rendered in the template. Instead, the template is responsible for querying data (from the page itself or related pages), using methods from the page model.
The main exception was collections, which I did use to structure commonly reused list of content. Those did have types in docblocks, but calling kirby()->collection('my-collection') breaks that chain. Maybe I should write my own collection loading code. Or just switch to adding methods to a DefaultPage model and call it a day.
Oh, by the way, I was looking for this static analysis tool for PHP type hints (supporting type hints, phpdoc and more features) that I remembered existing, and it took me way too long to locate it, so here it is if thatās useful for anyone: https://psalm.dev/
@fvsch or @texnixe Do either of you think that writing a Psalm plugin for Kirby would alleviate some or all of the trickier issues? I have liked using Psalm in the past, but beyond that I donāt know much about static analysis and how it can or canāt handle some of the more āmagicalā things Kirby seems to be doing.
This sounds excellent! Do you have any sense on how much this will fix? Is it possible that this is enough on its own, or would a Psalm plugin still be needed to properly tell it about custom autoloaders, parsing the txt files, etc.?