caseyamcl / sortable-tasks
动态编译和排序任务的抽象层
Requires
- php: ^7.4|^8.0
- marcj/topsort: ^1.1|^2.0
Requires (Dev)
- phpunit/phpunit: ^9.0
- squizlabs/php_codesniffer: ^3.5
README
A simple, un-opinionated PHP 7.4+ abstraction library to allow for the ordering of tasks. Features
- 任务是可以定义其他任务作为依赖项的服务类实例
- 适用于设置程序、确保HTTP中间件按顺序运行等库,其中任务的排序是任意确定的,但需要确定性地运行
- 基于
marcj/topsort
library 来启用对任务的排序,每个任务都定义在其自己的类中 - 不针对任务的实际运行方式;只是根据依赖关系排序它们,并按顺序运行
- PSR-4 和 PSR-12 兼容
结构
此库只包含两个文件
| SortableTask.php
| 任务的接口;包含两个定义依赖项的方法,depeondsOn
和 mustRunBefore
| | SortableTasksIterator.php
| 执行排序和其他工作的迭代器类;实现了 Iterable
和 Countable
|
安装
通过 Composer
$ composer require caseyamcl/sortable-tasks
用法
有关完整功能的示例,请参阅
tests/Fixture
目录。
展示此库的最佳方式是使用示例,因此我们将使用设置应用程序。在我们的假设应用程序中,设置任务可以按任何顺序注册,但它们将根据一组显式定义的依赖项以特定顺序运行。
首先,我们必须定义一个实现 SortableTask
接口的类
use SortableTasks\SortableTask; abstract class SetupStep implements SortableTask { abstract public function __invoke(): bool; }
请注意,我们不在抽象的 SetupStep
类中实现 dependsOn()
和 mustRunBefore()
方法。这意味着每个具体实现步骤都必须定义其依赖项。这是可选的,取决于实现 SortableTasks 的库。
如果大多数步骤不需要排序,则可以这样做
use SortableTasks\SortableTask; abstract class SetupStep implements SortableTask { abstract public function __invoke(): bool; // Provide default implementations of `dependsOn` and `mustRunBefore` that return empty arrays public static function dependsOn() : iterable { return []; } public static function mustRunBefore() : iterable { return []; } }
现在让我们创建一些设置步骤
class CheckConfigStep extends SetupStep { public static function dependsOn(): iterable { return []; // depends on nothing; can run anytime in the order of operations } public function __invoke(): bool { // do stuff, then.. return true; } } class CheckDbConnectionStep extends SetupStep { private DbConnector $dbConnector; public function __construct(DbConnector $dbConnector) { $this->dbConnector = $dbConnector; } public static function dependsOn(): iterable { return [CheckConfigStep::class]; } public static function mustRunBefore(): iterable { return [BuildContainerStep::class]; } public function __invoke(): bool { // do stuff, then.. return $this->dbConnector->checkConnection(); } } class BuildContainerStep extends SetupStep { private ContainerBuilder $containerBuilder; public function __construct(ContainerBuilder $containerBuilder) { $this->containerBuilder = $containerBuilder; } public static function dependsOn(): iterable { return [CheckConfigStep::class, CheckDbConnection::class]; } public function __invoke(): bool { // do stuff, then.. return $this->containerBuilder->buildContainer(); } }
现在我们已经有一些具体类,让我们将它们添加到 SortableTasksIterator 中
use SortableTasks\SortableTasksIterator; $iterator = new SortableTasksIterator(); // Notice that it doesn't matter in what order we add the steps; they will get sorted at runtime $iterator->add(new BuildContainerStep()); $iterator->add(new CheckDbConnectionStep()); $iterator->add(new CheckConfigStep()); // Tasks are sorted upon calling the iterator // Class names are the keys foreach ($iterator as $setupStepClassName => $setupStep) { if (! $setupStep()->__invoke()) { throw new SetupFailedException('Setup failed on step: ' . $setupStepClassName); } }
错误处理
在任务执行过程中可能会出现两个问题,它们都会抛出异常
- 循环依赖项;例如,任务 "A" 依赖于任务 "B",任务 "B" 依赖于任务 "A"。在这种情况下,会抛出
MJS\TopSort\CircularDependecyException
。 - 不存在的依赖项;例如,任务 "A" 依赖于任务 "B",但任务 "B" 未定义。在这种情况下,会抛出
MJS\TopSort\ElementNotFoundException
。
变更日志
有关最近更改的更多信息,请参阅 CHANGELOG。
测试
$ composer test
贡献
有关详细信息,请参阅 CONTRIBUTING。
安全
如果您发现任何安全相关的问题,请通过电子邮件 me@caseymclaughlin.com 而不是使用问题跟踪器。
鸣谢
许可
MIT 许可证(MIT)。有关更多信息,请参阅 许可文件。