sun / staticreflection
用于在发现之后场景下的静态 PHP 类代码反射。
Requires
- php: >=5.4.2
- ext-reflection: *
- ext-tokenizer: *
This package is auto-updated.
Last update: 2024-08-29 03:29:33 UTC
README
用于在发现之后场景下的静态 PHP 类代码反射。
这个 PHP 框架的实用库允许在已知文件系统位置的情况下,不将 PHP 类代码加载到内存中,来反射文件的头部。
静态反射对于过滤之前发现的类文件列表,例如接口或基类等常见方面非常有用。
ReflectionClass
提供与原生 \ReflectionClass
相同的 API。
原生 PHP 反射 容易失控,因为它不仅加载反射的类,还加载所有依赖类和接口。PHP 代码无法卸载。高内存消耗可能导致应用程序超过 PHP 的内存限制。— 静态反射避免将每个反射类的所有依赖和祖先类自动加载到内存中。
在最坏/理想的使用案例中,你只生成一个 可用 类的列表,而不立即使用它们(例如,用于用户选择或可交换的插件实现)。
示例 xhprof 差分结果
1,538 个候选类,其中 180 个接口、特性、抽象和其他辅助类被过滤掉
使用示例
-
先决条件:某些发现产生了一个类映射
{ "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" ... }
→ 你有一个
classname => pathname
映射。 -
过滤所有发现的类文件
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" } }
→ 你过滤了可用类的列表,而没有将所有代码加载到内存中。
-
这为什么重要
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, ... }
→ 仅加载了每个类/接口的 祖先。本身静态反射的类没有加载。
-
ProTip™ -
ReflectionClass::isSubclassOfAny()
要过滤一组常见的父类/接口,首先检查静态反射信息。只有在需要进一步检查的情况下才继续使用
isSubclassOf()
;例如。// 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; }
要求
- PHP 5.4.2+
限制
-
每个文件只能有一个类/接口/特性(PSR-2,PSR-0/PSR-4),且必须定义在文件中 第一个。
-
implementsInterface($interface)
返回TRUE
,即使$interface
是一个类。 -
\ReflectionClass::IS_IMPLICIT_ABSTRACT
不受支持,因为方法没有被分析。(只分析文件头部) -
\ReflectionClass::$name
是只读的,因此不可用。请使用getName()
代替。 -
调用任何其他未实现的
\ReflectionClass
方法会导致致命错误。父
\ReflectionClass
类可能会在需要时按需懒加载(PRs 欢迎)。ReflectionClass
已实现了所有技术上可以支持的方法。
注意
- StaticReflection 可以绕过删除注释的字节码缓存。
灵感
静态/反射
- Doctrine 的(静态)Reflection
- phpDocumentor 的 Reflection
- Zend Framework 的 Reflection
PHPDoc 标签/注释
- PHPUnit 的 Util\Test
- Doctrine 的 Annotations
- phpDocumentor 的 ReflectionDocBlock + Descriptor
- 库拉的PhpDocComment
- 菲利普·格雷厄姆的Annotations
许可证
MIT — 版权(c)2014 丹尼尔·F·库迪恩(sun)