PHP8.1中如何将应用程序目录路径传递给服务?

82 阅读2分钟

在这篇很短的文章中,我将向你展示两个简单的方法,如何将目录常量传递给服务,这是很基本的东西,你们大多数人都知道,但再次看到它总是无妨的。

假设我们有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) ,当你决定这样做时,你已经在使用公共的只读属性,这将带来一点不一致。