2

私は MVC PHP フレームワークを構築していますが、クラスに必要なものをロードするためのベスト プラクティスはどれでしょうか (他のクラスであろうと単純な構成であろうと)。

今日まで、私はシングルトン、レジストリ、そして最近では依存性注入コンテナーを使用してきました。多くの人が DI が進むべき道だと主張していますが、DI はコンポーネント間の結合の問題を別の場所に移しているように思えます。

シングルトンはグローバル状態を導入し、レジストリは密結合を導入し、DI は複雑さを導入します。私はまだ混乱しており、クラスを相互に配線する適切な方法を見つけることができません。

その間、私はカスタムソリューションを思いつきました。実際には解決策ではなく、コードからサービスのロードの実装を抽象化するだけです。

フレームワークのすべてのコンポーネントが他のサービスまたは構成をロードするために拡張する _load_service および _load_config メソッドを使用して抽象クラスを構築しました。

abstract class Base_Component {
    function _load_service($service) {
        // could be either
        return DI_container::getInstance()->$service;

        // or
        $class = '\services\\'.$service;
        return new $class;

        // or other implementation
    }
}

それらをロードする実装は、基本クラスの 1 つの場所だけに実装されるようになったため、少なくとも次のようなコード行をコンポーネントから削除しました。

$database = new Database(Registry::getInstance()->load('db_config'));

また

$database = DI_container::getInstance()->database;

データベースインスタンスが必要な場合は、これを行います

$database = $this->_load_service('database');

また、サービス ローダー、コンテナ、レジストリなどの実装は、以前使用していたコンテナ実装への呼び出しを変更するためにすべてのコードを検索することなく、単一のクラス メソッドで簡単に変更できます。

しかし、私が言ったように、クラスと構成をロードするためにどの方法を使用するかについては、よくわかりません。

あなたの意見は何ですか?

4

2 に答える 2

1

なぜ車輪を再発明するのですか?Pimpleを DIコンテナーとして使用し、そのドキュメントから使用方法を学びます。

または、Silexマイクロフレームワークをベースとして使用して、独自のフレームワークを作成します。これは Pimple 機能を拡張するため、依存性注入を使用できます。

あなたの質問に答えるために、クラスを結合せずに DI を使用する方法を次に示します。

interface ContainerInterface {
    public function getService($service_name);
    public function registerService($service_name,Closure $service_definition);
}

class Application {
    public function __construct(ContainerInterface $container) {
        $this->container= $container;
    }

    public function run() {
        // very simple to use!
        $this->container->getService('db')->someDatabaseQuery();
    }
}

$c = new My_DI_Container;

// Service definitions could be in a separate file
$c->registerService('db',function() { return new Database('some config'); });

// Then you inject your DI container into the objects that need it
$app = new Application($c);
$app->run(); // or whatever

このように、DI コンテナーは分離され、将​​来的には別の実装を使用できます。唯一の要件は、ContainerInterface を実装することです。

コンテナ オブジェクトがプッシュされているのであって、プルされていないことに注意してください。シングルトンの使用は避けてください。単一インスタンス オブジェクトを取得/設定するには、コンテナーを使用します (これはコンテナーの役割です)。コンテナー インスタンスを取得するには、コンストラクターを介してプッシュするだけです。

于 2011-11-09T17:30:59.223 に答える
0

あなたの質問に答えてください。PHP autoloadingを見てください。オートローディングを介してクラスを登録すると、require/includes をどこにでも配置する必要がなくなります。これは、RAD (迅速なアプリケーション開発) に本当にプラスの影響を与えます。

私の考え:

このような困難な作業を試みたことを称賛します。あなたのアプローチは、シングルトンやファクトリなどの優れたプラクティスに基づいているようです。

依存性注入は気にしません。OOP はカプセル化に基づいており、あるオブジェクトを別のオブジェクトに注入すると、カプセル化が解除されます。オブジェクトを別のオブジェクトに注入する場合、ターゲット オブジェクトは、注入されたオブジェクトに関して何も変更されていないことを「信頼」する必要があります。そうしないと、異常な動作が発生する可能性があります。

クラスの名前空間を検討してください (PHP の名前空間ではなく、Zend のようにフレームワークのプレフィックスとして Zend_ を使用します)。これにより、名前空間を登録できるようになり、クラスが呼び出されたときにオートローダーが適切なクラスが確実に読み込まれるようになります。 . これが Zend_Framework の仕組みです。詳細については、Zend_Loader_Autoloaderを確認してください。Symfony フレームワークは実際にこれをさらに一歩進めます。最初のリクエスト中に、クラス ファイルを探してすべての既知の場所を調べます。次に、クラスの配列とファイルへのパスを構築し、その配列をファイルに保存します (ファイル キャッシュ)。同じオーバーヘッド。フレームワークについて考慮すべきこと。

構成ファイルに関する限り、Symfony は YAML ファイルを使用しますが、これは非常に柔軟であることがわかりました。柔軟性を高めるために PHP コードを含めることもできます。Symfony は、使いやすいスタンドアロンのYAML パーサーを提供しています。キャッシュ レイヤーを追加し、解析済みの YAML ファイルをキャッシュすることでパフォーマンスを向上できるため、リクエストごとにファイルを解析する必要がなくなります。

ORM の上にフレームワークを構築していると仮定しています。私の推奨は、ORM の特定のバージョンに固有の機能ではありません。そうしないと、フレームワークがそのバージョンと結合され、ORM とフレームワークの両方を同時にアップグレードする必要があります。

他のフレームワークの内部を調べて、それぞれの最良のものを選択できるかどうかを確認することをお勧めします。堅牢で使いやすいフレームワークになります。

于 2011-11-08T21:48:59.087 に答える