PhpStorm 2019.3 Help

PhpStorm advanced metadata

Besides built-in “code awareness” capabilities, PhpStorm relies on external knowledge of code, which comes in the form of PHP stubs and the special advanced metadata files.

While stubs cover the Standard PHP Library components and common extensions, metadata files can be used for extending the PhpStorm functionality based on your own needs or project requirements. The basic metadata file, .phpstorm.meta.php, is bundled inside the PHP stubs package and located inside the meta folder.

Create metadata files inside your project

  1. Do any of the following:

    • Create a php file and name it .phpstorm.meta.php. You can create several such files and store them in different locations within the project. PhpStorm will collect and merge all the information from them.

    • Create a directory and name it .phpstorm.meta.php. Inside this directory, you can store any number of metadata files and name them arbitrarily.

  2. Inside a meta file, declare a PHPSTORM_META namespace and provide the metadata directives.

    namespace PHPSTORM_META { //metadata directives }

    Metadata directives specify how a certain function or method should be treated. Directives are written as regular PHP code, which allows for using the existing code editor features such as code completion, navigation and usages search, refactorings, and so on.

Define arguments accepted by a method

The expectedArguments directive instructs PhpStorm that a certain function accepts a certain set of arguments. The directive is specified by providing the function you are working with, the zero-based index of the argument, and the actual set of expected values, as follows:

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

You can enumerate expected arguments via the comma , or the pipe | bitwise operator. The former is used for functions expecting a single value out of the set of values, while the latter is used for functions expecting a bit mask of constants, such as json_encode.

As an example, let’s say you are implementing a Console command based on the symfony/console component. Sometimes there will be arguments that you want to pass to the command. In this example, a Symfony\Component\Console\Command::configure() method is being implemented:

Code completion before Expected Arguments is set

With expectedArguments in place, you can advise PhpStorm to expect the InputArgument::* constants here. To do this, add the following line to the metadata file:

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 );

Now, when you invoke code completion Ctrl+Space, the added constants are displayed in the suggestions list:

Code completion before Expected Arguments is set

Define possible return values

The expectedReturnValues directive instructs PhpStorm, which values a certain function or method returns. The directive is specified similarly to expectedArguments: you provide it with a function and the set of actual values (such sets can also be registered via ArgumentsSet) as follows:

expectedReturnValues(functionFQN, ...argumentsList);

After a function is specified, PhpStorm will provide code completion for function and static method calls in conditional statements.

Meta content and code completion for json_last_error

As an example, let’s say you are executing an HTTP request with one of the available PSR-7-compatible clients, and as the result, you’ll get a $response object of a class implementing \Psr\Http\Message\ResponseInterface. You may then want to check the status code and perform some suitable action. It may turn out handy to instruct PhpStorm that ResponseInterface::getStatusCode() returns a set of HTTP status codes:

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 ); }

When you invoke code completion Ctrl+Space inside a conditional statement, the added constants become available in the suggestions list:

Code completion for http request with expected return values

Create named sets of arguments or return values

For some functions, the list of possible arguments’ values can be quite large. What’s more, different functions can accept the same sets of values. If you provide the list of expected arguments for such functions, the metadata file will grow excessively large. It will also contain duplicate entries, and the amount of work required to maintain it will also double.

To handle this, inside a metadata file, you can use two directives: registerArgumentsSet and argumentsSet. The registerArgumentsSet directive accepts two arguments: the arbitrary name of the set of arguments and the list of actual values contained in this set. Values are specified the same way as the list of expected arguments: depending on the function or method you are working with, you can enumerate them via the comma , or the pipe | bitwise operator.

To register the set of arguments, specify the directive as follows:

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

Having registered the single set of arguments, you can reference it from within expectedArguments by using the argumentsSet directive:

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

As an example, consider the ini_get and ini_set functions both accepting the same set of php.ini directives.

You can register the set of arguments as follows:

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

Having done that, you can reference this set from within expectedArguments both for ini_get and ini_set:

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

Define method's return type

In many cases, it is not possible to clearly infer the return type of the function based on the function's code itself. By using the override directive, you can explicitly instruct PhpStorm that the specified function returns the entity of a certain type based on the provided arguments.

The directive is specified as follows:

override(functionFQN, overrideDirective);

Where overrideDirective can be one of the following:

  • type: sets the function's return type to the type of the passed argument.

  • elementType: if the passed argument is an array, sets the function's return type to the type of the elements contained in the array.

  • map: sets an arbitrary mapping between the argument value and the function's return type.

Use the argument's type

The type directive instructs PhpStorm that the function's return type matches the type of its first argument. The directive is specified as follows:

override(functionFQN, type(0));

As an example, consider the following code sample:

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

Initially, you won't get code completion in this and similar expressions:

Method return type not overridden

You can address this by adding the following line to the metadata file:

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

This way, you instruct PhpStorm that the doActionA() method's return type matches the type of its first argument, which is class B in our case. The corresponding code completion entry becomes available:

Method return type overridden

Use the array element's type

The elementType directive is applicable for functions that accept an array as their first argument. The directive instructs PhpStorm that the function's return type matches the type of the elements contained in the array. Note that it only works for arrays having elements of the same type. The directive is specified as follows:

override(functionFQN, elementType(0));

As an example, consider the following code sample:

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];

Initially, you won't get code completion in this and similar expressions:

Method return element type not overridden

You can address this by adding the following line to the metadata file:

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

This way, you instruct PhpStorm that if an array is passed to doActionA(), then this method's return type matches the type of the array elements, which is class B in our case. The corresponding code completion entry becomes available:

Method return element type overridden

Provide arbitrary types mapping

The map directive lets you set an arbitrary mapping between the argument's value and the function's return type. By using this directive, you can implement generic support for the factory pattern in PhpStorm, and thus get coding assistance when working with common PHP frameworks (such as Magento, Doctrine, Kohana, ZF2, and so on). The directive is specified as follows:

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

Where key is a string literal, global constant, or class constant, and value is a ::class constant or a pattern literal. Inside the pattern literal, you can use the @ symbol that will resolve to the literal value of the provided argument.

As an example, consider the following code sample.

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

By using the map metadata directive, you can instruct PhpStorm, which return type is expected from (new Factory())->get() depending on the passed argument:

Passing a string literal

When the "special" string literal is passed, an instance of \Exception is returned:

override(\Factory::get(), map([ "special" => \Exception::class, ]));
Method return type overridden via literal

Passing a global constant

When the myConst global constant is passed, an instance of AClass is returned:

override(\Factory::get(), map([ \myConst => \AClass::class, ]));
Method return type overridden via literal

Passing a class constant

When the classConstant class constant is passed, an instance of BClass is returned:

override(\Factory::get(), map([ \Factory::classConstant => \BClass::class, ]));
Method return type overridden via literal

Using lookup patterns

The @Class lookup pattern allows for resolving AClass if the 'A' literal is passed, or BClass if 'B' is passed:

override(\Factory::get(), map([ '' => '@Class' ]));
Method return type overridden via literal

Legacy metadata format (deprecated)

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 ]; }
Last modified: 27 March 2020