rfc:aliases_by_reflection

PHP RFC: Access to aliases definition by reflection

Introduction

PHP 5.3 brought namespaces and aliasing/importing by use operator. Aliases are expanded to FQN (Fully Qualified Name) in the compile-time phase and user-land code has no access to aliases definition. Today, aliases are often used in annotations and annotations are used by the advanced programming techniques. The need to expand aliases to FQN in user-land code arose. This RFC brings the aliases definition into user-land.

The RFC does not deal with function and constant aliases brought by PHP 5.6.

Problem to solve

use Library\Http;
 
class Factory
{
	/** @return Http\Client */
	public function createClient()
	{
		return new Http\Client;
	}
}

It is very difficult to find out, if class name Http\Client in @return annotation is already FQN or if it is an alias.

Libraries solve this problem roughly in the same way: “tokenize source code and search for T_USE tokens.” It is very expensive, error prone and caching is needed. Example solutions:

There are more libraries which more or less solve the problem. Searching for T_USE on Github makes overview.

Proposal

Add ReflectionClass::getDefinedAliases() and ReflectionFunctionAbstract::getDefinedAliases() methods. Other reflection classes are out of aliases scope. The return value of methods is an array with lowercased alias as a key and imported name as a value.

Defined aliases can be obtained from reflection of class, interface, trait, function, class method or closure. Usage is following:

use Library\Http;
 
class C {}
 
use Library\Tools as LT;
 
function f() {}
 
$rc = new ReflectionClass('c');
$rf = new ReflectionFunction('f');
 
var_dump($rc->getDefinedAliases());
/*
array(1) {
  ["http"] => string(12) "Library\Http"
}
*/
 
var_dump($rf->getDefinedAliases());
/*
array(2) {
  ["http"] => string(12) "Library\Http"
  ["lt"]   => string(13) "Library\Tools"
}
*/

Backward Incompatible Changes

Possible BC break can occur in libraries which extend ReflectionClass or ReflectionFunctionAbstract. But I didn't find any.

Proposed PHP Version(s)

RFC is proposed for PHP 7.

Impact on performance and memory usage

In current PHP version, aliases are parsed and kept only in compile-time. The aliases definition is discarded on the compile-time end. Patch (mentioned below) keeps HashMap with definitions for runtime. Worse performance and higher memory consumption are expected.

Keeping aliases definition will increase memory consumption. Value depends on many factors:

  • how many aliases are defined
  • how long are the aliases definitions (string lengths)
  • how many classes, interfaces, traits, functions and closures definitions exist in one namespace in one file

Following code increases memory consumption for 320 bytes.

use A as B;
 
class C {}

Adding one more alias, memory consumption increases for next 48 bytes:

use A as B;
use C as D;
 
class C {}

Adding next class, memory consumption increases for next 264 bytes:

use A as B;
 
class C {}
class D {}

Method getDefinedAliases() exists on ReflectionMethod class too due to inheritance. But adding class methods does not increase memory consumption, because aliases definition is internally kept only for class.

Measurements

Five measurements on real libraries and application follow.

The first two measurements are done on Nette Framework v2.2.3 and Symfony Framework v2.5.5 (including Doctrine v2.4.6) libraries. The measurements are a little bit synthetic, because every file was loaded (require_once) in a test script. It does not happen in real life application, classes are lazy loaded.

The next two measurements are done on clean WordPress 4 installation. The first one is a request for a homepage with one post. The second one is a request for a post editing page.

The last measurement is done on CLI application ApiGen 4.0.0-RC2. The API documentation is generated for mentioned Nette Framework.

For a time performance measurement, every measurement step has been done 1000 times and averaged. Only the ApiGen run only 100 times due to long duration. The Time column is a percentage difference between patched and unpatched version.

Classes Interfaces Traits Functions All Files Memory PHP7 Memory RFC Diff Time
Nette Framework 256 42 0 5 303 265 5612kB 5711kB 99kB 1.8% 2.3%
Symfony Framework 2422 374 3 56 2855 2813 33744kB 34796kB 1053kB 3.1% 1.4%
WordPress Homepage 67 0 0 1647 1714 84 8900kB 8964kB 64kB 0.7% 0.6%
WordPress Edit Page 78 0 0 2038 2116 109 11683kB 11687kB 4kB 0.04% N/A
ApiGen 226 46 0 28 300 284 28430kB 28898kB 469kB 1.6% 0.5%

PHP7 means commit 51c90e.

Patch

The RFC implementation can be found at https://github.com/milo/php-src/tree/reflectionAliases. Patch is kindly provided by Nikita Popov.

Patch does not contain opcache integration.

Vote

Should be reflection in PHP 7 extended for a proposed getDefinedAliases() functionality?

This is not a language change. 50% + 1 votes are needed to get 'accepted'.

Access to aliases definition by reflection
Real name Yes No
bwoebi (bwoebi)  
derick (derick)  
dragoonis (dragoonis)  
gwynne (gwynne)  
levim (levim)  
lstrojny (lstrojny)  
malukenho (malukenho)  
mbeccati (mbeccati)  
pierrick (pierrick)  
salathe (salathe)  
stas (stas)  
Final result: 1 10
This poll has been closed.

The vote starts on 11/26/2014 and ends on 12/22/2014. 50% + 1 majority required.

rfc/aliases_by_reflection.txt · Last modified: 2017/09/22 13:28 (external edit)