3 回答

TA貢獻1946條經(jīng)驗 獲得超4個贊
容器嘗試解析(并創(chuàng)建)類的新實例\DI\Container,因為這不是 Slim 使用的接口。相反,嘗試聲明 PSR-11 ContainerInterface。然后 DIC 應該傳遞正確的容器實例。
例子
use Psr\Http\Message\ServerRequestInterface;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
相同的“規(guī)則”適用于請求處理程序接口。
完整示例:
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class Foo
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function __invoke(
Request $request,
Response $response,
array $args = []
): Response {
var_dump($this->container);
}
}
最后一點:注入容器是一種反模式。請改為在構造函數(shù)中顯式聲明所有類依賴項。
為什么注入容器(在大多數(shù)情況下)是一種反模式?
在 Slim 3 中,“服務定位器”(反模式)是注入整個(Pimple)容器并從中獲取依賴項的默認“風格”。
服務定位器(反模式)隱藏了類的真正依賴。
服務定位器(反模式)也違反了 SOLID 的控制反轉 (IoC) 原則。
問:我怎樣才能讓它變得更好?
A:使用composition和(顯式)構造函數(shù)依賴注入。
依賴注入是一種將其協(xié)作者傳遞給對象的編程實踐,而不是對象本身創(chuàng)建它們。
由于斯利姆4您可以使用現(xiàn)代化的DIC像PHP-DI和league/container與真棒“自動裝配”功能。這意味著:現(xiàn)在您可以在構造函數(shù)中顯式聲明所有依賴項,并讓 DIC 為您注入這些依賴項。
更明確地說:“組合”與 DIC 的“自動裝配”功能無關。您可以將組合與純類一起使用,而無需容器或其他任何東西。自動裝配功能僅使用PHP 反射類為您自動解析和注入依賴項。

TA貢獻1821條經(jīng)驗 獲得超6個贊
這是 PHP-DI 如何自動注冊自身的結果。在撰寫此答案時,PHP-DI 容器DI\Container在創(chuàng)建時將自身自動注冊到 key以及三個實現(xiàn)的接口(請參閱Container.php 的這些行)。因此,如果您針對構造函數(shù)參數(shù)DI\Container或它實現(xiàn)的三個接口之一(包括Psr\Container\ContainerInterface)鍵入提示,則 PHP-DI 能夠自行解析。
?問題是使用self::class(該文件的第 110 行)使DI\Container密鑰以某種方式進行了硬編碼,因此盡管您正在創(chuàng)建DI\Container( Config) 的子類,但容器仍像以前一樣注冊到相同的密鑰。解決這個問題的一種方法是讓容器知道它Config也應該由自己解決。我看到兩個選項:
將容器注冊到與其類名相同的鍵,就像做什么DI\Container一樣(這似乎是正確的方法)
實例化后手動注冊容器
這是一個完全有效的示例:
<?php
require '../vendor/autoload.php';
use DI\Container;
use Slim\Factory\AppFactory;
use Psr\Container\ContainerInterface;
use DI\Definition\Source\MutableDefinitionSource;
use DI\Proxy\ProxyFactory;
class Config extends Container
{
public function __construct(
MutableDefinitionSource $definitionSource = null,
ProxyFactory $proxyFactory = null,
ContainerInterface $wrapperContainer = null
) {
parent::__construct($definitionSource, $proxyFactory, $wrapperContainer);
// Register the container to a key with current class name
$this->set(static::class, $this);
}
}
class Foo
{
public function __construct(Config $config)
{
die($config->get('custom-key'));
}
}
$config = new Config();
$config->set('custom-key', 'Child container can resolve itself now');
// Another option is to not change Config constructor,
// but manually register the container in intself with new class name
//$config->set(Config::class, $config);
AppFactory::setContainer($config);
$app = AppFactory::create();
$app->get('/', \Foo::class);
$app->run();
請注意:正如最佳實踐所建議的那樣,您不應針對具體類(DI\Container或您的Config類)鍵入提示,而應考慮針對接口 ( Psr\Container\ContainerInterface)鍵入提示。

TA貢獻1824條經(jīng)驗 獲得超5個贊
問題是濫用了名為autowiring的 PHP-DI 功能:
自動裝配是一個奇特的詞,它代表了一些非常簡單的東西:容器自動創(chuàng)建和注入依賴項的能力。
為了實現(xiàn)這一點,PHP-DI 使用 PHP 的反射來檢測構造函數(shù)需要哪些參數(shù)。
如果您使用工廠方法來創(chuàng)建容器,您可以禁用自動裝配并停止“奇怪”行為:
$builder = new ContainerBuilder(Config::class);
$builder->useAutowiring(false);
$config = $builder->build();
但我想更好的解決方案是學習如何正確使用自動裝配:)
我忽略了所有這些細節(jié),因為我的代碼最初是為 Slim/3 編寫的,它使用Pimple作為硬編碼默認容器。我錯誤地認為它們的工作方式相似,但盡管是容器解決方案,但兩個庫卻大不相同。
- 3 回答
- 0 關注
- 222 瀏覽
添加回答
舉報