问题描述
我的设置包括一个带有类的 lib
文件夹和一个带有 PHP 文件的 view
文件夹,用于生成输出。这些视图被导入到一个类似于这样的 View
类中:
class View {
public function render(string $basename,Array $params) : string {
extract($params,EXTR_PREFIX_INVALID,'v');
ob_start();
include sprintf('%s/views/%s.PHP',dirname(__DIR__),$basename);
$out = ob_get_contents();
ob_end_clean();
return $out;
}
}
在这种情况下,我对 Psalm 基本上有两个问题:
-
对于
View::render
,它报告一个UnresolvableInclude
。我什至可以输入$basename
类似@param "view1"|"view2"|"about" $basename
没有效果。无法解析的包含仍然存在。
-
extract()
将$params
的内容放在包含视图文件的本地范围内。这让我有<?=escape($foo)?>
在我的视图文件中使用
$params === ['foo' => 'bar']
“标记”。然而,Psalm 并没有赶上这一点,并报告了很多UndefinedGlobalVariable
问题。
我的问题:我如何将视图文件和变量告诉 psalm?或者,我如何重新构建此代码,以便 psalm 可以为我测试?
解决方法
在 Psalm 的 repo 中有一个演示 TemlateChecker plugin,它似乎做了类似的事情:它查看视图文件中的 docblock 以获取像 @variablesfrom ClassName::method
这样的标签,并使它们在模板文件中可用。或者只是来自该方法的 $this
变量的属性,不确定。 Psalm 文档中也提到了这一点:Checking non-PHP files。
或者,您可以将模板包装到一个最小的方法/函数中,因为从技术上讲,视图只是一个接受一堆变量并返回一个字符串的函数:https://psalm.dev/r/66898ee87f
<?php class HomePageView { // view starts here
/** @param list<string> $sections */
public function render(
string $title,array $sections
): string { ob_start();
?>
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<?php foreach ($sections as $section): ?>
<section><?=$section?></section>
<?php endforeach; ?>
</body>
</html>
<?php return ob_get_contents(); }} // view ends here ?>
这样,任何分析代码的工具(包括但不限于 Psalm)都能够理解它。