私たちのためにすべてを行うフレームワークで作業するときにも同じことが起こりますが、私はそれらがどのようにそれを行うかを知り、必要に応じて動作を変更できるようにしたいと思います。 残念ながら、ドキュメントは、それがどれほど優れていても( そしてSymfony 2はすでに優れています )、この「魔法」をすべて使用する方法を示していますが、本質全体は明らかにしていません。
この記事は、アプリケーションの初期化方法と「Symfony2カーネル」とは何かを理解しようとする試みです。
大きなテキストが気に入らない人のために、主要なコンポーネントの簡単な概要と実行されるアクションの簡単な説明がすぐに添付されます。
簡単なプロセスの説明
クリック可能
1.すべての要求は、フロントコントローラー(FrontController)によって受け入れられます。
2. autoloadクラスを構成します(autoload)。
3.環境に応じてカーネルが作成されます。
4.カーネルが起動します。
1.バンドルのリストが初期化されます。
2.依存性注入コンテナが作成されます。
1.メインパラメータを使用してコンテナが作成されます。
2.各バンドルはビルドコンテナを変更します。
3.アプリケーション構成がロードされています。
4.コンテナがコンパイルされます。
1.拡張機能が処理されています。
2.パラメーターへの参照は実際の値に置き換えられます。
3.コンテナは読み取り専用モード(凍結)になります。
3.バンドルが起動します。
フロントコントローラー
フロントコントローラーは通常のスクリプトです。 例は、 標準のSymfony2ディストリビューションからのスクリプトです。
- app / console -CLIを介したアプリケーションへのアクセス。
- web / app.php -Webを介したアプリケーションへのアクセス。
- web / app_dev.php-開発モードのWebを介したアプリケーションへのアクセス。
これらすべてのフロントコントローラーは、同じ原理に基づいて構築されています。
- 自動ロードは、クラスローダーの登録でスクリプトを接続することによって構成されます。
- クラスキャッシュが使用される場合があります(1つのファイルに収集された頻繁に使用されるクラス)。
- カーネルが起動します。
カーネル
カーネルはKernelInterfaceインターフェースを実装するクラスであり、そのタスクは環境を初期化することです。 コアは、依存性注入コンテナー(理論は、たとえばFowlerから収集できます)とバンドルシステムの2つの主要なコンポーネントに基づいています。 このバンドルは、Symfony 1.xのプラグインに類似しています。 バンドルの詳細については、公式ドキュメントをご覧ください。 もちろん、カーネルインターフェース自体に加えて、標準の抽象的なカーネル実装もあります。これについては、主に後で説明します。
初期化コードは次のようになります。
// init bundles $this->initializeBundles(); // init container $this->initializeContainer(); foreach ($this->getBundles() as $bundle) { $bundle->setContainer($this->container); $bundle->boot(); }
- (4.1)initializeBundles-バンドルに関する情報を収集します(開発者がKernelInterface :: registerBundlesを介してアプリケーションに登録するもの。 標準配信の例を参照してください)。
- (4.2)initializeContainer -DIコンテナーを作成し、それにデータを入力します。
- (4.3)各バンドルが起動されます。
コンテナの初期化
この段階の結果、完全に使用可能なコンテナが作成され、読み取り専用モードに切り替わります。 このプロセスは4つのサブステップに分かれています。
- コンテナー( ContainerBuilder )が作成され、そこに標準のカーネルパラメーターが配置されます:メインディレクトリへのパス、環境パラメーター(環境、デバッグ)など。
- バンドルごとにビルドが開始されます。この段階で、バンドルにはコンテナを変更する機会が与えられます
- 開発者が定義した構成が追加されます(カーネルregisterContainerConfigurationを介して)。 標準パッケージでは、このメソッドは非常にシンプルに見えます。
public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); }
- 最後に、コンテナがコンパイルされます。実際のパラメータ値が置換されます。 「コンパイラパス」* ( CompilerPass)が実行されます。これらは、バンドルによって追加された変更を実行するものです(後で詳しく説明します)。 コンテナは「凍結」されています。 読み取り専用モードになり、その後変更しようとすると例外がスローされます 。
コンテナバンドルの変更
上記のように、コンパイルプロセス中に、各バンドルには共通のコンテナを変更する機会があります。 変更する主な方法は、 コンパイラパスを追加することです
コンパイラーパス
コンパイル段階で、コンテナは一連のパスを実行して、コンテンツを最終状態に戻します。 パスは、 CompilerPassInterfaceインターフェースの実装であり、6種類(実行順)になります: merge、beforeOptimization、最適化、beforeRemoving、remove、afterRemoving-デフォルトでは、コンパイラー構成にはすでにパスワードのセットが含まれています。
- before * / after *は、カスタム「パス」の単なる「フック」であり、標準のものでは使用されません(デフォルトで追加)。
- merge-コンテナ拡張を処理します
- 最適化 -コンテナーを最適化します。例には、ResolveInterfaceInjectorsPass( インターフェース注入の変換)、CheckCircularReferencesPass(コンテナー内の循環参照のチェック)が含まれます。
- 削除 -RemoveUnusedDefinitionsPassなどの未使用のサービスを削除します(未使用のプライベートサービスを削除します)
バンドルでは、CompilerPassがコンテナ内のタグの処理に最もよく使用されます。 標準のTwigBundleの例:
$definition = $container->getDefinition('twig'); $calls = $definition->getMethodCalls(); $definition->setMethodCalls(array()); foreach ($container->findTaggedServiceIds('twig.extension') as $id => $attributes) { $definition->addMethodCall('addExtension', array(new Reference($id))); } $definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls));
コンテナ拡張
コンテナはシステムの中心的な要素であり、実際、アプリケーションのすべての機能がそこに集中しているため、機能を追加するには、必要なサービスとパラメータをコンテナに入れる必要があります。 このような変更の便宜上、 コンテナ拡張機能があります(上記の特別な「マージ」パスで処理されます)。
ExtensionsはExtensionInterfaceインターフェイスの実装であり、抽象Extensionクラスはルーチンアクションを削減し、便利なメソッドを追加します。 通常、拡張機能は次のように機能します。
- サービスの定義とデフォルトのパラメーターは、拡張構成ファイル(ほとんどの場合xmlファイル)からロードされます。
- アプリケーションに定義された拡張設定を処理し、デフォルト値を上書きします。
- 1つのファイルにアセンブリするためのクラスが登録されています(フロントコントローラーで言及されている1つのファイルの同じクラスキャッシュ)
拡張設定の例( app / config / config.yml ):
# Twig Configuration twig: debug: %kernel.debug% strict_variables: %kernel.debug%
この構成では、 twig ( ExtensionInterface :: getAlias() )という名前の拡張機能( ExtensionInterface :: load() )に、対応するセクションで定義されたパラメーターを渡す必要があることを示しています。
バンドル拡張機能の接続は非常に簡単です。対応する名前( DependencyInjection \ BundleNameExtension )でクラスを作成するだけで、 拡張機能:: build()メソッドコードは拡張機能自体をロードします(主なことは親メソッドと継承者を呼び出すことを忘れないことです)。
バンドルを起動
そして最後の段階はバンドルの発売です。 実際、ほとんどのバンドルはこの段階では何もしません。コンテナでは実行できないアクションを実行するように設計されています。 たとえば、この段階で、メインのSymfony2バンドル(FrameworkBundle)は、この記事で複数回言及されたクラスキャッシュをロードします。
おわりに
これにより、Symfony2アプリケーションの初期化プロセスは完了したと見なすことができます。すべての準備手順が完了し、コンテナーに必要な機能がすべて含まれています。 コンテナから必要なサービスを取得し、そのメソッドを呼び出してアプリケーションを実行します。
読者はおそらく、かなり複雑でリソースを大量に消費する初期化プロセスを心配するでしょうが、それほど悪くはありません。 Symfony2は柔軟性とともに速度を忘れないため、すぐに多くの最適化ソリューションを提供します。 そのため、たとえば、すべての設定を含むクラスを作成することでコンテナーを作成するプロセス全体がキャッシュされ、さまざまなパラメーターの多くの構成、コンテナーコンパイラなどを読み込むのではなく、次回それを呼び出す(デバッグモードの場合) 生成されたクラスがロードされるだけで、すぐに使用可能なコンテナオブジェクトが作成されます。
著者から
これで、Symfony2の荒野への最初の飛び込みは終わりです。 Symfony2に関するこの種の記事が読者の興味を引くなら、フレームワークの内部、個々のコンポーネント、人気のあるバンドルを分析して、これらすべてを一連の記事に変えることができます。 さらに、Habréに長期滞在しているにもかかわらず、これは私の最初の記事です。 私は書くよりも話すのが好きですが、自分の考えを表現するこの方法で自分自身を教育しようとしています。 したがって、資料のプレゼンテーションに関する直接的なフィードバックに非常に感謝します。 強調する方が良いもの、少ないもの。 おそらくより多くの図とコード例が必要です。 サブジェクト領域に精通している人にもっと頼るか、誰にでもはっきりわかるように説明しようとするなど。