在这篇很短的文章中,我将向你展示两个简单的方法,如何将目录常量传递给服务,这是很基本的东西,你们大多数人都知道,但再次看到它总是无妨的。
假设我们有CronTaskExecutor ,通过shell_exec 函数从数据库中执行cron任务,该函数需要我们应用程序的路径,正如你所看到的,该服务需要DI容器的$logger 服务和$appDir 字符,我们必须从我们的配置文件中传递。
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private string $appDir,
) {}
}
services:
- CronTaskExecutor(appDir: %appDir%)
没有必要手动添加服务到配置中,因为我们有内置的搜索扩展,可以根据Facade, Repository, Factory, Executor, Manager, Sender, Helper等后缀自动将我们的类注册为服务。而我们不得不编辑配置文件的唯一原因是我们需要传递%appDir% 常量。
想象一下,你有一个相当大的项目,你经常要使用目录路径,如%tempDir% %appDir% 或%vendorDir% ,也许还有你的自定义目录路径,用于备份、媒体等等。每当你需要一些目录路径时,你就不得不在你的配置中添加服务。
避免这种情况的直接解决方案是创建服务,它将为其他服务提供所有重要的项目目录,并且只注册一次,当服务需要一些目录路径时,我们将简单地注入我们的DirectoryProvider 服务。这是一个添加了$backupDir 的服务类的例子。
(在本文中,PHP 8.1的只读属性只是为了避免带有getters的长类。)
declare(strict_types=1);
namespace App\Model;
class DirectoryProvider
{
public readonly string $backupDir;
public function __construct(
public readonly string $appDir,
public readonly string $tempDir,
public readonly string $vendorDir,
) {
$this->backupDir = $this->appDir . '/../backups';
}
}
现在我们必须像这样在配置文件中注册该服务。
services:
- App\Model\DirectoryProvider(
appDir: %appDir%,
tempDir: %tempDir%,
vendorDir: %vendorDir%,
)
所以有了这个服务,我们就不再需要在配置文件中添加与应用程序目录一起工作的服务,因为现在我们可以注入我们的DirectoryProvider ,而使用$this->directoryProvider->appDir 。
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private DirectoryProvider $directoryProvider,
) {}
public function execute(CronTask $task): void
{
$appDir = $this->directoryProvider->appDir;
}
}
最后的想法
我在例子中使用了PHP8.1(即将发布)中的新语法,只是为了简化类并在文章中腾出一些空间,我仍然喜欢使用getters的语法,原因是你可以向方法传递一些参数,例如getMediaDir(MediaType::Images) ,当你决定这样做时,你已经在使用公共的只读属性,这将带来一点不一致。