そうしないでください!以前に議論されましたが、最終的にはメーリングリストの議論を読むことができます。これにはいくつかの良い例もあります。
クラスTest
が何らかの理由でサービスロケーターにアクセスする必要があると仮定すると、正しいアプローチは、サービスロケーターをハード依存としてインスタンス化することです。
use Zend\ServiceManager\ServiceLocatorInterface;
class Test extends AbstractModel
{
// ...
public function __construct(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function doFoo()
{
return $this->serviceLocator->get('FooService')->foo();
}
// ...
}
このようにして、それをファクトリでインスタンス化するか$test = new Test($serviceLocator);
、ファクトリで定義して、サービスロケータ自体にインスタンスを提供させることができます。
namespace MyApp;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
class Module implements ServiceProviderInterface
{
public function getServiceConfig()
{
return array(
'factories' => array(
'Test' => function ($serviceLocator) {
return new \Test($serviceLocator);
},
),
);
}
}
これにより、基本的'Test'
にアプリケーション全体でサービスを利用できるようになります。
とにかく、作成したものには2つの大きな欠陥があります。
サービスロケーションを使用する際に注意する必要がある落とし穴があります。これは、その性質上、サービスの場所自体の問題です。
- コードをサービスロケーターにバインドしていますが、他のサービスのインスタンスを取得することはクラスの問題ではない場合があります。それらが明確に定義され、常に同じである場合は、代わりにそれらを注入します
- クラスのサービス名に文字列を使用しています。そのため、サービス名が完全に異なる可能性がある別のアプリケーションにコードを移植することは非常に困難です。
- サービスロケーターの障害(サービスが見つかりません)が原因でコードが失敗する可能性があります。この失敗は、必要な場合にのみサービスにアクセスしているという事実によって遅れる可能性があります。複雑なアプリケーションでデバッグするのは簡単ではないかもしれません
これにより、モデル/エンティティでサービス(およびサービスロケーター)を使用しようとしています。この誤解/誤用は、ZF1のように、多くのロジックがDBレコードを表すオブジェクトの一部であるアクティブレコードパターンに慣れているという事実に起因している可能性があります。Zend_Db
ZF2のサービスは定義と使用が非常に簡単なので、そのようなロジックをサービスに移動してください。上で説明したのは、値オブジェクトまたはエンティティに似たクラスであり、複雑なビジネスロジックを含めるべきではありません。
また、興味がある場合は、サービスの場所の代わりにIOCを使用する必要がある理由についてのブログ投稿を書きました(2番目の段落では、サービスの場所の落とし穴について説明しています)。