我希望我正确地理解了你的问题。事实上,我几周前刚刚经历过这件事。对我来说,这是一些有趣的事情。
Reading through this laravel snippet
帮助我理解了接口和依赖注入是如何工作的。这篇文章讨论了合同与外观,以及为什么你可能希望使用其中一种而不是另一种。
听起来你想用一个
Filesystem
实例,可以读取远程文件(S3等)或本地文件。由于文件系统只能是远程的或本地的(不是组合的),我认为正确的做法是使用一个接口以相同的方式与两者交互,然后允许用户/开发人员(通过依赖项注入首选项)在声明一个
文件系统
.
// Classes used
use League\Container\Container;
use League\Container\ReflectionContainer;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
// Create your container
$container = new Container;
/**
* Use a reflection container so devs don't have to add in every
* dependency and can autoload them. (Kinda out of scope of the question,
* but still helpful IMO)
*/
$container->delegate((new ReflectionContainer)->cacheResolutions());
/**
* Create available filesystems and adapters
*/
// Local
$localAdapter = new Local($cacheDir);
$localFilesystem = new Filesystem($localAdapter);
// Remote
$client = new S3Client($args);
$s3Adapter = new AwsS3Adapter($client, 'bucket-name');
$remoteFilesystem = new Filesystem($s3Adapter);
/**
* This next part is up to you, and many frameworks do this
* in many different ways, but it almost always comes down
* to declaring a preference for a certain class, or better
* yet, an interface. This example is overly simple.
*
* Set the class in the container to have an instance of either
* the remote or local filesystem.
*/
$container->add(
FileSystemInterface::class,
$userWantsRemoteFilesystem ? $remoteFilesystem : $localFilesystem
);
Magento 2 does this
通过编译
di.xml
文件,并通过声明另一个类的首选项来读取要替换的类。
Symfony does this
在一个
有点
类似的时尚。对我来说,他们是医生有点粗糙,但在经过几天(以及联赛)的筛选之后,我终于站到了另一边,非常了解正在发生的事情。
使用您的服务:
假设应用程序中有依赖注入,并且希望连接到
文件系统
在你的阅读课上,你会包括
FilesystemInterface
作为构造函数依赖项,当它被注入时,它将使用通过
$container->add($class, $service)
use League\Flysystem\FilesystemInterface;
class Reader
{
protected $filesystem;
public function __construct(FilesystemInterface $filesystem)
{
$this->filesystem = $filesystem;
}
public function getFromLocation($location)
{
/**
* We know this will work, because any instance that implements the
* FilesystemInterface will have this read method.
* @see https://github.com/thephpleague/flysystem/blob/dab4e7624efa543a943be978008f439c333f2249/src/FilesystemInterface.php#L27
*
* So it doesn't matter if it is \League\Flysystem\Filesystem or
* a custom one someone else made, this will always work and
* will be served from whatever was declared in your container.
*/
return $this->filesystem->read($location);
}
}