PhpStorm 2025.2 Help

PhpStorm 高级元数据

除了内置的“代码感知”功能外,PhpStorm 还依赖于代码的外部知识,这些知识以 PHP stubs和特殊的高级元数据文件的形式存在。

虽然 stubs 覆盖了标准 PHP 库组件和常见扩展,但元数据文件可用于根据您的需求或项目要求扩展 PhpStorm 的功能。 基本元数据文件 .phpstorm.meta.php 包含在 PHP stubs 包中,并位于 元信息 文件夹中。

在项目中创建元数据文件

  1. 执行以下任意操作:

    • 创建一个 php 文件并将其命名为 .phpstorm.meta.php 。 您可以创建多个这样的文件,并将它们存储在项目中的不同位置。 PhpStorm 将收集并合并其中的所有信息。

    • 创建一个目录并将其命名为 .phpstorm.meta.php 。 在此目录中,您可以存储任意数量的元数据文件,并任意命名它们。

  2. 在元文件中,声明一个 PHPSTORM_META 命名空间并提供元数据指令。

    namespace PHPSTORM_META { //metadata directives }

    元数据 指令指定应如何处理某个函数或方法。 指令以常规 PHP 代码的形式编写,这允许使用现有的代码编辑器功能,例如 代码补全 Ctrl+Space导航用法搜索重构等。

    元文件中的代码补全
  • 如果函数的行为通过 expectedArgumentsexitPointoverride指令被更改,PhpStorm 会在编辑器边栏的函数声明旁显示 元数据图标 图标。

    单击 元数据图标 图标以导航到元文件中的相应指令。

    编辑器边栏中的元数据指示器

定义方法接受的参数

expectedArguments 指令告知 PhpStorm 某个函数接受一组特定的参数。 通过提供您正在处理的函数、参数的零基索引以及实际的预期值集合来指定指令,如下所示:

expectedArguments(functionFQN, argumentIndex, ...argumentsList);

您可以通过逗号 , 或管道符 | 按位或运算符枚举预期参数。 前者用于期望从值集合中选择单个值的函数,而后者用于期望常量位掩码的函数,例如 json_encode

例如,假设您正在基于 symfony/console组件实现一个 Console 命令。 有时会有一些参数需要传递给命令。 在此示例中,正在实现一个 Symfony\Component\Console\Command::configure() 方法:

设置预期参数之前的代码补全

通过 expectedArguments ,您可以建议 PhpStorm 在此处预期 InputArgument::* 常量。 为此,请将以下行添加到元数据文件中:

expectedArguments( \Symfony\Component\Console\Command\Command::addArgument(), 1, \Symfony\Component\Console\Input\InputArgument::OPTIONAL, \Symfony\Component\Console\Input\InputArgument::REQUIRED, \Symfony\Component\Console\Input\InputArgument::IS_ARRAY );

现在,当您调用代码补全 Ctrl+Space 时,添加的常量会显示在建议列表中:

设置预期参数之前的代码补全

定义可能的返回值

expectedReturnValues 指令告知 PhpStorm 某个函数或方法返回哪些值。 该指令的指定方式与 expectedArguments类似:您为其提供一个函数和实际值的集合(此类集合也可以通过 ArgumentsSet注册),如下所示:

expectedReturnValues(functionFQN, ...argumentsList);

指定函数后,PhpStorm 将在条件语句中为函数和静态方法调用提供代码补全。

json_last_error 的元内容和代码补全

例如,假设您正在使用一个可用的 PSR-7 兼容客户端执行 HTTP 请求,结果将获得一个实现 \Psr\Http\Message\ResponseInterface的类的 $response 对象。 然后,您可能希望检查状态码并执行一些适当的操作。 告知 PhpStorm ResponseInterface::getStatusCode() 返回一组 HTTP 状态码可能会很方便:

namespace PHPSTORM_META { expectedReturnValues(\Psr\Http\Message\ResponseInterface::getStatusCode(), \Symfony\Component\HttpFoundation\Response::HTTP_OK, \Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST, \Symfony\Component\HttpFoundation\Response::HTTP_INTERNAL_SERVER_ERROR ); }

当您在条件语句中调用代码补全 Ctrl+Space 时,添加的常量会在建议列表中可用:

带有预期返回值的 HTTP 请求代码补全

创建命名的参数集或返回值集

对于某些函数,可能的参数值列表可能非常大。 更重要的是,不同的函数可以接受相同的值集合。 如果您为此类函数提供 预期参数的列表,元数据文件将变得过于庞大。 它还会包含重复条目,并且维护所需的工作量也会加倍。

为了解决这个问题,在元数据文件中,您可以使用两个指令: registerArgumentsSetargumentsSetregisterArgumentsSet 指令接受两个参数:参数集的任意名称和该集中包含的实际值列表。 值的指定方式与 预期参数的列表相同:根据您正在处理的函数或方法,您可以通过逗号 , 或管道符 | 按位或运算符枚举它们。

要注册参数集,请按以下方式指定指令:

registerArgumentsSet('argumentsSetName', ...argumentsList);

注册单个参数集后,您可以通过使用 argumentsSet 指令从 expectedArguments 中引用它:

expectedArguments(functionFQN, 0, argumentsSet('argumentsSetName'));

例如,考虑 ini_getini_set 函数,它们都接受相同的 php.ini 指令集合。

您可以按以下方式注册参数集:

registerArgumentsSet('ini_values', ...iniValuesList);

完成后,您可以从 expectedArguments 中引用此集合,用于 ini_getini_set

expectedArguments(\ini_get(), 0, argumentsSet('ini_values')); expectedArguments(\ini_set(), 0, argumentsSet('ini_values'));

定义退出点

通过使用 exitPoint 指令,您可以明确告知 PhpStorm 指定的函数充当退出点。 此类函数的调用被视为终止调用,类似于 PHP 内置的 exitdie函数的调用。 指令的指定方式如下:

exitPoint(functionFQN( [optionalArguments] ));

其中 optionalArguments 可以是字符串字面量或类常量。 如果提供了可选参数,则只有带有此参数的函数调用会被视为退出点。 否则,执行将正常继续。

例如,考虑以下代码示例:

class Application { public function terminate($param) { exit(); } public function run() { $this->terminate('foo'); echo "Hello"; $this->terminate('bar'); echo " world!"; } }

要将 terminate('bar') 方法调用标记为退出点,请将以下行添加到元数据文件中:

exitPoint(Application::terminate('bar'));

结果是,带有 bar 参数的 terminate 调用将充当退出点。 运行 方法的最后一行因此将被视为不可达:

退出点方法调用

定义方法的返回类型

在许多情况下,无法根据函数本身的代码清楚地推断出函数的返回类型。 通过使用 override 指令,您可以明确告知 PhpStorm 指定的函数根据提供的参数返回某种类型的实体。

指令的指定方式如下:

override(functionFQN, overrideDirective);

其中:

  • functionFQN 是函数或类方法的完全限定名称。 __get()__call()__callStatic() 魔术方法也受支持。

  • overrideDirective 是以下之一:

    • type :将函数的返回类型设置为传递参数的类型。

    • elementType :如果传递的参数是数组,则将函数的返回类型设置为数组中包含的元素的类型。

    • map :在参数值和函数的返回类型之间设置任意映射。

使用参数的类型

type 指令告知 PhpStorm 函数的返回类型与其参数的类型匹配。 指令的指定方式如下:

override(functionFQN, type(argumentIndex));

其中 argumentIndex 是参数的零基索引,其类型应用作函数的返回类型。

例如,考虑以下代码示例:

class A { public function doActionA($a) { return $a; } } class B { public function doActionB($b) { return $b; } }

最初,您不会在此类表达式中获得代码补全:

方法返回类型未被覆盖

您可以通过将以下行添加到元数据文件中来解决此问题:

override(A::doActionA(0), type(0));

通过这种方式,您告知 PhpStorm doActionA() 方法的返回类型与其第一个参数的类型匹配,在我们的例子中是类 B。 相应的代码补全条目变得可用:

方法返回类型已被覆盖

使用数组元素的类型

elementType 指令适用于接受数组作为参数的函数。 该指令告知 PhpStorm 函数的返回类型与数组中包含的元素的类型匹配。 请注意,它仅适用于具有相同类型元素的数组。 指令的指定方式如下:

override(functionFQN, elementType(argumentIndex));

其中 argumentIndex 是包含数组的参数的零基索引,其元素的类型用作函数的返回类型。

例如,考虑以下代码示例:

class A { public function doActionA($a) { return $a; } } class B { public function doActionB($b) { return $b; } } $B1 = new B(); $B2 = new B(); $arrB = [$B1, $B2];

最初,您不会在此类表达式中获得代码补全:

方法返回元素类型未被覆盖

您可以通过将以下行添加到元数据文件中来解决此问题:

override(A::doActionA(0), elementType(0));

通过这种方式,您告知 PhpStorm 如果将数组传递给 doActionA() ,则此方法的返回类型与数组元素的类型匹配,在我们的例子中是类 B。 相应的代码补全条目变得可用:

方法返回元素类型已被覆盖

提供任意类型映射

map 指令允许您在参数值和函数的返回类型之间设置任意映射。 通过使用此指令,您可以在 PhpStorm 中实现对 工厂模式的通用支持,从而在使用常见 PHP 框架(如 Magento、Doctrine、Kohana、ZF2 等)时获得编码辅助。 指令的指定方式如下:

override(functionFQN, map([ key => value, ... ]));

其中 key 是字符串字面量、全局常量或类常量, value::class 常量或模式字面量。 在模式字面量中,您可以使用 @ 符号,该符号将解析为提供的参数的字面值。 您还可以提供 联合类型 ,即由管道符 | 分隔的多个类型。

例如,请考虑以下代码示例。

define('myConst', 'GlobalConstant'); class Factory { const classConstant = 'ClassConstant'; public function get($name) { return $name; } public function __call($name, $arguments) {} } class AClass { public function doActionA() {} } class BClass { public function doActionB() {} } $result = (new Factory())->get();

通过使用 map 元数据指令,您可以告知 PhpStorm 根据传递的参数, (new Factory())->get() 预期的返回类型。 您还可以为通过 __call() 魔术方法调用的方法指定返回类型。

传递字符串字面量

当传递 "special" 字符串字面量时,将返回 \Exception 的实例:

override(\Factory::get(), map([ "special" => \Exception::class, ]));
通过字符串字面量覆盖方法返回类型

传递全局常量

当传递 myConst 全局常量时,将返回 AClass 的实例:

override(\Factory::get(), map([ \myConst => \AClass::class, ]));
通过全局常量覆盖方法返回类型

传递类常量

当传递 classConstant 类常量时,将返回 BClass 的实例:

override(\Factory::get(), map([ \Factory::classConstant => \BClass::class, ]));
通过类常量覆盖方法返回类型

使用查找模式

@Class 查找模式允许在传递 'A' 字面量时解析 AClass ,或在传递 'B' 时解析 BClass

override(\Factory::get(), map([ '' => '@Class' ]));
通过字面量覆盖方法返回类型

为魔术方法构造动态返回类型

@Class 查找模式允许在调用 a() 方法时解析 AClass ,或在调用 b() 时解析 BClass

override(\Factory::__call(), map([ '' => '@Class' ]));
通过字面量覆盖方法返回类型

使用联合类型

AClass|BClass 联合类型声明允许同时解析 AClassBClass

override(\Factory::get(), map([ '' => 'AClass|BClass' ]));
通过字面量覆盖方法返回类型

为 SQL 语言注入中的表名设置动态前缀

许多内容管理系统和框架支持使用表前缀,这些前缀在应用程序配置级别定义。 在代码中,表名在 SQL 字符串中通过前缀标记指定。 当应用程序的数据库层处理这些字符串时,此类名称将替换为包含前缀的实际表名。

通过使用 sql_injection_subst 元数据指令,您可以为 注入的 SQL 字符串设置将前缀标记替换为实际前缀的规则。 结果是,PhpStorm 将为数据库表名提供代码补全,并在 运行 SQL 查询时使用它们。

指令的指定方式如下:

override(sql_injection_subst(), map([ "prefix_marker" => "replacement" ]));

请考虑以下示例:数据库包含两个表, app_usersapp_products ,它们使用 app_ 表前缀。 在代码中, [prefix ]#__ 前缀标记用于引用这些表。 最初,注入的 SQL 字符串中的表名未被识别,因此无法为它们提供代码补全。

SQL 注入中的未知表名

要注册数据库前缀,请将以下内容添加到元数据文件中:

override( sql_injection_subst(), map( [ "[prefix]" => "app_", "#__" => "app_" ]));;

结果是,PhpStorm 会自动将前缀标记替换为实际前缀,并且表名变得可用:

SQL 注入中的已解析表名

旧版元数据格式(已弃用)

namespace PHPSTORM_META { $STATIC_METHOD_TYPES = [ // we make sections for scopes \ServiceLocatorInterface::get('') => [ // STATIC call key to make static (1) & dynamic (2) calls work "special" instanceof \Exception, // "KEY" instanceof Class maps KEY to Class ], new \ServiceLocatorInterface => [ // NEW INSTANCE is to make ArrayAccess (3) style factory work "special" instanceof \Exception, ], \ServiceLocatorInterface::getByPattern('') => [ "" == "@Iterator", // "ignored" == "PatternWith@" substitutes @ with arg value ], \globalFactoryFunction('') => [ // (4) works also with functions ], // if key is not found its used as type name in all cases ]; }
最后修改日期: 2025年 9月 26日