PhpStorm 2019.2 Help

PhpStorm advanced metadata

Factory methods

The factory design pattern is commonly used in PHP frameworks (e.g. Magento, Doctrine, Kohana, ZF2, and so on). PhpStorm provides generic support for the factory pattern via advanced metadata files.

Suppose you have something like the following "service" or "helper" provider interfaces/objects.

<?php interface ServiceLocatorInterface {     function get($name); //You call this to get your helper depending on argument     function getByPattern($name); } class ServiceManager implements ServiceLocatorInterface {     function get($name) {         return new $name; //simplest test example implementation     }       function getByPattern($name) {         return new $name;     } } $serviceManager = (new ServiceManager());     function globalFactoryFunction($param) { return new $param; }

You can make the following cases work by using the additional metadata file.

<?php //(1) static factory call $getStatic = ServiceManager::get("special"); //(2) non-static factory $getDynamic = $serviceManager->get("special"); //(3) ArrayAccess style factory $getFromArray = $serviceManager["special"]; //class name constant $getByClassNameConst = $serviceManager->get(Exception::class); $getByClassNameConstFromArray = $serviceManager["Exception"]; //"fallback" to direct class name $getWithFallback = $serviceManager->get("Exception"); $getWithFallbackArray = $serviceManager["Exception"]; //look up by expressions $byPattern = $serviceManager->getByPattern("Seekable" /*Iterator*/); //(4) $getFromStaticFunction = globalFactoryFunction("Exception");   //this is all resolved and green! $getByClassNameConst->getCode(); $getWithFallback->getCode(); $getByClassNameConstFromArray->getCode(); $getFromArray->getCode(); $getDynamic->getCode(); $byPattern->seek(1);   class Foo { /**  * @var ServiceManager  */ protected $serviceManager; function test() {             $worksThroughProperties = $this->serviceManager->get(Exception::class);             $worksThroughProperties->getCode(); // same in class         } }

It is recommended to store it in a .meta.php file under the project root. In PhpStorm version 2016.2 and later, you can have multiple separate files stored in a folder named .phpstorm.meta.php.


<?php namespace PHPSTORM_META {                                // we want to avoid the pollution   // this is a saner and self-documented format for PhpStorm 2016.2 and later //Try QuickDoc on these "magic" functions, or even Go to definition!   override( \ServiceLocatorInterface::get(0),         // method signature //argument number is ALWAYS 0 now.   map( [ //map of argument value -> return type     "special" => \Exception::class,                //Reference target classes by ::class constant     \ExampleFactory::EXAMPLE_B => ExampleB::class,  // FYI, we can now support class constant argument values     \EXAMPLE_B => \ExampleB::class,              // and global constants too                                                 //non-mapped value, e.g. $getByClassNameConst case above will be returned automatically   ]));     //pattern example. `@` is replaced by argument literal value. override(\ServiceLocatorInterface::getByPattern(0),     map([         '' => '@Iterator|\Iterator',     ]));   //basicaly the same as get, just for array["arg"] lookups override(new \ServiceLocatorInterface,     map([         "special" => \Exception::class,     ])); }

PHP code is used as a config, so that we can use the existing API to analyse it. The specific format is chosen also to facilitate the existing editor features to help as much as possible: code completion works, references are resolved, usage search and refactoring work too.

More dynamic return type possibilities

<?php   //below is the example of couple more meta expressions bundled into PhpStorm for better standard library support   override(\array_filter(0), type(0)); override(\array_reduce(0), elementType(0));

Packaging metadata/stub files into plugin

You can now package these into public plugins by adding XML descriptor and uploading the ZIP file to the plugins repository, see example at

Legacy metadata format (deprecated)

PhpStorm version 2016.1 and earlier use a different metadata format (now deprecated).

<?php namespace PHPSTORM_META {                                // we want to avoid the pollution // this is legacy format for 2016.1 and EARLIER // This file is not a CODE, it makes no sense and won't run or validate // Its AST serves IDE as DATA source to make advanced type inference decisions.   $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: 23 September 2019