承接 sun/staticreflection 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

sun/staticreflection

Composer 安装命令:

composer require sun/staticreflection

包简介

Static PHP class code reflection for post-discovery scenarios.

README 文档

README

Static PHP class code reflection for post-discovery scenarios.

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

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

ReflectionClass provides the same API as the native \ReflectionClass.

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.

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

Example xhprof diff result:

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

\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:

    {
      "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.

  2. Filter all discovered class files:

    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.

  3. Why this matters:

    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.

  4. ProTip™ - ReflectionClass::isSubclassOfAny()

    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.:

    // 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.

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

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

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

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

    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.

Notes

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

Inspirations

Static/Reflection:

PHPDoc tags/annotations:

License

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

统计信息

  • 总下载量: 24
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2014-06-06

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固