2017 © Pedro Peláez
 

library staticreflection

Static PHP class code reflection for post-discovery scenarios.

image

sun/staticreflection

Static PHP class code reflection for post-discovery scenarios.

  • Tuesday, July 1, 2014
  • by sun
  • Repository
  • 1 Watchers
  • 1 Stars
  • 14 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 3 Versions
  • 0 % Grown

The README.md

StaticReflection Build Status Code Coverage Code Quality

Static PHP class code reflection for post-discovery scenarios., (*1)

This utility library for PHP frameworks allows to reflect the file header of a PHP class without loading its code into memory, if its filesystem location is known already (e.g., via discovery/classmap)., (*2)

Static reflection is useful to filter a large list of previously discovered class files for common aspects like interfaces or base classes., (*3)

ReflectionClass provides the same API as the native \ReflectionClass., (*4)

Native PHP Reflection can easily grow out of control, because it not only loads the reflected class, but also all dependent classes and interfaces. PHP code cannot be unloaded. A high memory consumption may cause the application to exceed PHP's memory limit. — Static reflection avoids to (auto-)load all dependencies and ancestor classes of each reflected class into memory., (*5)

In the worst/ideal use-case, you're only generating a list of available classes, without using them immediately (e.g., for user selection or swappable plugin implementations)., (*6)

Example xhprof diff result:, (*7)

1,538 candidate classes, of which 180 interfaces, traits, abstract and other helper classes are filtered out:, (*8)

\ReflectionClass ReflectionClass Diff Diff%
Number of Function Calls 64,747 202,783 138,036 213.2%
Incl. Wall Time (microsecs) 2,514,801 3,272,539 757,738 30.1%
Incl. CPU (microsecs) 2,480,415 3,120,020 639,605 25.8%
Incl. MemUse (bytes) 108,805,120 10,226,160 -98,578,960 -90.6%
Incl. PeakMemUse (bytes) 108,927,216 10,347,608 -98,579,608 -90.5%

Usage Example

  1. Prerequisite: Some discovery produces a classmap:, (*9)

    {
      "Sun\StaticReflection\ReflectionClass":
        "./src/ReflectionClass.php",
      "Sun\Tests\StaticReflection\ReflectionClassTest":
        "./tests/src/ReflectionClassTest.php",
      "Sun\Tests\StaticReflection\Fixtures\Example":
        "./tests/fixtures/Example.php",
      "Sun\Tests\StaticReflection\Fixtures\Base\ImportedInterface":
        "./tests/fixtures/Base/ImportedInterface.php"
      ...
    }
    

    → You have a classname => pathname map., (*10)

  2. Filter all discovered class files:, (*11)

    use Sun\StaticReflection\ReflectionClass;
    
    $list = array();
    foreach ($classmap as $classname => $pathname) {
      $class = new ReflectionClass($classname, $pathname);
    
      // Only include tests.
      if (!$class->isSubclassOf('PHPUnit_Framework_TestCase')) {
        continue;
      }
    
      // …optionally prepare them for a listing/later selection:
      $doc_comment = $class->getDocComment();
      $list[$classname] = array(
        'summary' => $doc_comment->getSummary(),
        'covers' => $doc_comment->getAnnotations()['coversDefaultClass'][0],
      );
    }
    echo json_encode($list, JSON_PRETTY_PRINT);
    
    {
      "Sun\Tests\StaticReflection\ReflectionClassTest": {
        "summary": "Tests ReflectionClass.",
        "covers": "\Sun\StaticReflection\ReflectionClass"
      }
    }
    

    → You filtered the list of available classes, without loading all code into memory., (*12)

  3. Why this matters:, (*13)

    array_walk($classmap, function (&$pathname, $classname) {
      $pathname = class_exists($classname, FALSE) || interface_exists($classname, FALSE);
    });
    echo json_encode($classmap, JSON_PRETTY_PRINT);
    
    {
      "Sun\Tests\StaticReflection\ReflectionClassTest": false,
      "Sun\Tests\StaticReflection\Fixtures\Example": false,
      "Sun\Tests\StaticReflection\Fixtures\ExampleInterface": true,
      "Sun\Tests\StaticReflection\Fixtures\Base\Example": true,
      ...
    }
    

    → Only the ancestors of each class/interface were loaded. The statically reflected classes themselves did not get loaded., (*14)

  4. ProTip™ - ReflectionClass::isSubclassOfAny(), (*15)

    To filter for a set of common parent classes/interfaces, check the statically reflected information first. Only proceed to isSubclassOf() in case you need to check further; e.g.:, (*16)

    // Static reflection.
    if (!$class->isSubclassOfAny(array('Condition\FirstFlavor', 'Condition\SecondFlavor'))) {
      continue;
    }
    // Native reflection of ancestors (if the reflected class has any).
    if (!$class->isSubclassOf('Condition\BaseFlavor')) {
      continue;
    }
    

Requirements

  • PHP 5.4.2+

Limitations

  1. Only one class/interface/trait per file (PSR-2, PSR-0/PSR-4), which must be defined first in the file., (*17)

  2. implementsInterface($interface) returns TRUE even if $interface is a class., (*18)

  3. \ReflectionClass::IS_IMPLICIT_ABSTRACT is not supported, since methods are not analyzed. (only the file header is analyzed), (*19)

  4. \ReflectionClass::$name is read-only and thus not available. Use getName() instead., (*20)

  5. Calling any other \ReflectionClass methods that are not implemented (yet) causes a fatal error., (*21)

    The parent \ReflectionClass class might be lazily instantiated on-demand in the future (PRs welcome). ReflectionClass does implement all methods that can be technically supported already., (*22)

Notes

  • StaticReflection may work around bytecode caches that strip off comments.

Inspirations

Static/Reflection:, (*23)

PHPDoc tags/annotations:, (*24)

License

MIT — Copyright (c) 2014 Daniel F. Kudwien (sun), (*25)

The Versions

01/07 2014

dev-codeclimate

dev-codeclimate

Static PHP class code reflection for post-discovery scenarios.

  Sources   Download

MIT

The Requires

  • php >=5.4.2
  • ext-tokenizer *
  • ext-reflection *

 

by Daniel F. Kudwien (sun)

parser phpdoc docblock annotations reflection token autoload discovery

29/06 2014

dev-master

9999999-dev

Static PHP class code reflection for post-discovery scenarios.

  Sources   Download

MIT

The Requires

  • php >=5.4.2
  • ext-tokenizer *
  • ext-reflection *

 

by Daniel F. Kudwien (sun)

parser phpdoc docblock annotations reflection token autoload discovery

26/06 2014

1.0.0

1.0.0.0

Static PHP class code reflection for post-discovery scenarios.

  Sources   Download

MIT

The Requires

  • php >=5.4.2
  • ext-tokenizer *
  • ext-reflection *

 

by Daniel F. Kudwien (sun)

parser phpdoc docblock annotations reflection token autoload discovery