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
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.
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 Ctrl+Space, navigation and usages search, refactorings, and so on.
Navigate to a metadata directive
If a function's behavior is altered via the expectedArguments, exitPoint, or override directives, PhpStorm displays the
icon in the editor gutter next to the function declaration.
Click the
icon to navigate to the corresponding directive in a meta file.
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:
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 Code completion before Expected Arguments is set](https://resources.jetbrains.com/help/img/idea/2022.1/ps_symfony-console-before-expected.png)
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:
Now, when you invoke code completion Ctrl+Space, the added constants are displayed in the suggestions list:
![Code completion before Expected Arguments is set Code completion before Expected Arguments is set](https://resources.jetbrains.com/help/img/idea/2022.1/ps_symfony-console-after-expected.png)
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:
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 Meta content and code completion for json_last_error](https://resources.jetbrains.com/help/img/idea/2022.1/ps_json_last_error-completion.png)
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:
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 Code completion for http request with expected return values](https://resources.jetbrains.com/help/img/idea/2022.1/ps_http-request-with-expected-arguments-2.png)
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:
Having registered the single set of arguments, you can reference it from within expectedArguments
by using the argumentsSet
directive:
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:
Having done that, you can reference this set from within expectedArguments
both for ini_get
and ini_set
:
Define exit points
By using the exitPoint
directive, you can explicitly instruct PhpStorm that the specified function acts as an exit point. The call of such a function is treated as a terminating call, similarly to the calls of the PHP built-in exit or die functions. The directive is specified as follows:
Where optionalArguments
can be a string literal or a class constant. If an optional argument is provided, only the function call with this argument will be treated as an exit point. Otherwise, execution will continue normally.
As an example, consider the following code sample:
To mark the terminate('bar')
method call as an exit point, add the following line to the metadata file:
As a result, the terminate
call with the bar
argument provided will act as an exit point. The last line of the run
method will therefore be treated as unreachable:
![Exit Point Method Call Exit Point Method Call](https://resources.jetbrains.com/help/img/idea/2022.1/ps_exit_point_method_call.png)
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:
Where:
functionFQN
is the fully qualified name of a function or a class method. The__get()
,__call()
, and__callStatic()
magic methods are also supported.overrideDirective
is 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 argument. The directive is specified as follows:
Where argumentIndex
is the zero-based index of the argument whose type should be used as the function's return type.
As an example, consider the following code sample:
Initially, you won't get code completion in this and similar expressions:
![Method return type not overridden Method return type not overridden](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_type_before.png)
You can address this by adding the following line to the metadata file:
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 Method return type overridden](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_type_after.png)
Use the array element's type
The elementType
directive is applicable for functions that accept an array as their 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:
Where argumentIndex
is the zero-based index of the argument containing an array whose elements' type is used as the function's return type.
As an example, consider the following code sample:
Initially, you won't get code completion in this and similar expressions:
![Method return element type not overridden Method return element type not overridden](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_element_type_before.png)
You can address this by adding the following line to the metadata file:
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 Method return element type overridden](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_element_type_after.png)
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:
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. You can also provide union types, that is, several types separated by the pipe |
symbol.
As an example, consider the following code sample.
By using the map
metadata directive, you can instruct PhpStorm, which return type is expected from (new Factory())->get()
depending on the passed argument. You can also specify the return types for methods invoked via the __call()
magic method.
Pass a string literal
When the "special"
string literal is passed, an instance of \Exception
is returned:
![Method return type overridden via string literal Method return type overridden via string literal](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_special_literal.png)
Pass a global constant
When the myConst
global constant is passed, an instance of AClass
is returned:
![Method return type overridden via global constant Method return type overridden via global constant](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_global_constant.png)
Pass a class constant
When the classConstant
class constant is passed, an instance of BClass
is returned:
![Method return type overridden via class constant Method return type overridden via class constant](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_class_constant.png)
Use lookup patterns
The @Class
lookup pattern allows for resolving AClass
if the 'A'
literal is passed, or BClass
if 'B'
is passed:
![Method return type overridden via literal Method return type overridden via literal](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_lookup_pattern.png)
Construct a dynamic return type for a magic method
The @Class
lookup pattern allows for resolving AClass
if the a()
method is called, or BClass
if b()
is called:
![Method return type overridden via literal Method return type overridden via literal](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_lookup_pattern_magic.png)
Use union types
The AClass|BClass
union type declaration allows for resolving both AClass
and BClass
:
![Method return type overridden via literal Method return type overridden via literal](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_map_union_type.png)
Set up dynamic prefixes for table names in SQL language injections
Many content management systems and frameworks support the use of table prefixes, which are defined at the application configuration level. In the code, tables' names are specified with prefix markers within SQL strings. When the database layer of the application processes these strings, such names are replaced with the actual table names including a prefix.
By using the sql_injection_subst
metadata directive, you can set up the rules for replacing the prefix markers with actual prefixes in injected SQL strigs. As a result, PhpStorm will provide code completion for the database tables' names as well as use them when running SQL queries.
The directive is specified as follows:
Consider the following example: the database contains two tables, app_users
and app_products
, which are using the app_
table prefix. In the code, the [prefix ]
and #__
prefix markers are used to refer to these tables. Initially, the tables' names in injected SQL strings are not recognized, so code completion for them is not available.
![Unknown table name in SQL injection Unknown table name in SQL injection](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_sql_injection_table_unknown.png)
To register the database prefixes, add the following to the metadata file:
As a result, PhpStorm automatically substitutes the prefix marker with the actual prefix and tables' names become available:
![Resolved table name in SQL injection Resolved table name in SQL injection](https://resources.jetbrains.com/help/img/idea/2022.1/ps_override_sql_injection_table_resolved.png)