kafkiansky / discovery
从应用程序自动加载类映射中查找接口、特性和类。
Requires
- php: ^8.1
Requires (Dev)
- phpunit/phpunit: ^9.5
- vimeo/psalm: ^4.23
README
内容
安装
composer require kafkiansky/discovery
用法
通常需要找到所有实现特定接口、继承特定类或使用特定特性的类。这些信息可以用于,例如,在IOC容器中实现自动装配。为了避免解析整个项目,可以使用autoload_classmap.php
文件中的类信息,这是composer
用于优化时使用的。
Class Implements
查找实现特定接口的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassImplements(\Stringable::class))); // discover all interfaces that implement the Stringable interface.
查找实现所有特定接口的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassImplements([\Stringable::class, \ArrayAccess::class])));
查找实现特定接口之一的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassImplements(interfaces: [\Stringable::class, \ArrayAccess::class], implementsAll: false)));
Class Extends
查找扩展特定类的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassExtends; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassExtends(\Exception::class)));
Class Uses
查找使用特定特性的所有类。此规则递归地在父特性和特性的特性中搜索所需的特性
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassUses; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassUses(SomeTrait::class)));
Class Has Attributes
查找使用特定属性的所有类。
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassHasAttributes; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover(new ClassHasAttributes(SomeAttribute::class)));
全部
查找满足规则列表的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\All; use Kafkiansky\Discovery\Rules\ClassExtends; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover( new All(new ClassImplements(\Stringable::class), new ClassExtends(\Exception::class)) ));
任意
查找至少满足列表中一个规则的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\Any; use Kafkiansky\Discovery\Rules\ClassExtends; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover( new Any(new ClassImplements(\Stringable::class), new ClassExtends(\Exception::class)) ));
无
查找不满足任何规则的所有类
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\None; use Kafkiansky\Discovery\Rules\ClassExtends; use Kafkiansky\Discovery\Rules\ClassImplements; $discovery = new Discovery(new ComposerClassmapClassLoader(__DIR__)); var_dump($discovery->discover( new None(new ClassImplements(\Stringable::class), new ClassExtends(\Exception::class)) ));
加载器约束
如果您想指定可以加载的类,可以使用LoaderConstraint
接口实现。默认情况下,有Kafkiansky\Discovery\CodeLocation\Composer\LoadOnlyApplicationCode
类,它只加载来自您的composer.json
文件中autoload.psr4
部分的命名空间匹配的类。
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassImplements; use Kafkiansky\Discovery\CodeLocation\Composer\LoadOnlyApplicationCode; $applicationRoot = __DIR__; $discovery = new Discovery( new ComposerClassmapClassLoader($applicationRoot, new LoadOnlyApplicationCode($applicationRoot)) ); var_dump($discovery->discover(new ClassImplements(\Stringable::class)));
Composer加载器
默认情况下,ComposerClassmapClassLoader
在vendor/composer/autoload_classmap.php
路径中搜索autoload_classmap.php
并强制它。如果您想传递自己的类映射加载器,可以使用withClassMapLoader
方法覆盖默认加载器
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassExtends; use Kafkiansky\Discovery\CodeLocation\Composer\LoadOnlyApplicationCode; use Kafkiansky\Discovery\FileNotFound; $applicationRoot = __DIR__; $loader = new ComposerClassmapClassLoader($applicationRoot); $loader = $loader->withClassMapLoader(function (string $path): array { return [FileNotFound::class => $path . '/src/FileNotFound.php']; }); $discovery = new Discovery($loader); var_dump($discovery->discover(new ClassExtends(\Exception::class)));
数组加载器
为了测试目的,您可以使用Kafkiansky\Discovery\CodeLocation\ArrayClassLoader
<?php use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\Rules\ClassExtends; use Kafkiansky\Discovery\CodeLocation\ArrayClassLoader; use Kafkiansky\Discovery\FileNotFound; $discovery = new Discovery(new ArrayClassLoader([ FileNotFound::class, ])); var_dump($discovery->discover(new ClassExtends(\Exception::class)));
性能优化
在生产中,您可能希望缓存匹配规则的类以避免不必要的检查。然后您必须使用DiscoveryWithCache
<?php use Kafkiansky\Discovery\Cache\DiscoveryWithCache; use Kafkiansky\Discovery\Cache\Adapter\FilesystemCache; use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\CodeLocation\Composer\LoadOnlyApplicationCode; use Kafkiansky\Discovery\Rules\ClassImplements; $appPath = __DIR__; $cacheDir = __DIR__.'/cache'; $discovery = new DiscoveryWithCache( new Discovery(new ComposerClassmapClassLoader($appPath), new LoadOnlyApplicationCode($appPath)), new FilesystemCache($cacheDir) ); $discovery->discover(new ClassImplements(\Stringable::class));
或者,如果您想有条件地缓存,请使用cacheIf
可调用函数来指定何时缓存和何时不缓存
<?php use Kafkiansky\Discovery\Cache\DiscoveryWithCache; use Kafkiansky\Discovery\Cache\Adapter\FilesystemCache; use Kafkiansky\Discovery\Discovery; use Kafkiansky\Discovery\CodeLocation\Composer\ComposerClassmapClassLoader; use Kafkiansky\Discovery\CodeLocation\Composer\LoadOnlyApplicationCode; use Kafkiansky\Discovery\Rules\ClassImplements; $appPath = __DIR__; $cacheDir = __DIR__.'/cache'; $discovery = new DiscoveryWithCache( new Discovery(new ComposerClassmapClassLoader($appPath), new LoadOnlyApplicationCode($appPath)), new FilesystemCache(directory: $cacheDir, cacheIf: function (): bool { return \get_env('APP_ENV') === 'production'; }); ); $discovery->discover(new ClassImplements(\Stringable::class));
测试
$ composer test
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。