今日、新しいプロジェクトを開始するときの重要な決定の1つは、適切なフレームワークを選択することです。今日では、複雑なWebアプリケーションをゼロから構築することを想像するのは難しくなっています。
Web開発で人気のある言語の多くには、RubyのRuby onRailsやPythonのDjangoなどの「デフォルト」フレームワークがあります。ただし、PHPにはそのような単一のデフォルトはなく、複数の一般的なオプションから選択できます。
による Googleトレンド そして GitHub 、最も人気のあるPHPフレームワークは 13.7kの星とのSymfony そして 29kの星を持つLaravel (この記事の執筆時点)。
この記事では、これら2つのフレームワークを比較し、それぞれにシンプルで日常的な機能を実装する方法を示します。このようにして、実際の例のコードを並べて比較できます。
この記事は、強力なPHPスキルとMVCアーキテクチャパラダイムの理解を前提としていますが、SymfonyまたはLaravelの経験は必要ありません。
Laravelについて話すときは、Laravelバージョン4以降を指します。 Laravel 4は2013年にリリースされ、フレームワークの完全な書き直しを表しています。フレームワークの機能は、すべてが1つの巨大なコードリポジトリにあるのではなく、Composerで管理される個別のコンポーネントに分離されました。
Laravelは、習得、読み取り、保守が容易なシンプルで美しい構文を備えた、迅速な開発のためのフレームワークであると宣言しています。これは2016年に最も人気のあるフレームワークです。 Googleトレンド 、他のフレームワークの3倍の人気があります。 GitHub 、競合他社の2倍の星があります。
Symfony 2は2011年にリリースされましたが、Symfony 1と混同しないでください。Symfony1は、基本的な原則が異なるまったく異なるフレームワークでした。 FabienPotencierがSymfony2を作成し、現在のバージョンは3.2です。これはSymfony 2のインクリメンタルバージョンです。したがって、これらは単にSymfony2 / 3と呼ばれることがよくあります。
Laravel 4と同様に、Symfony2は分離されたコンポーネントのセットとして設計されています。ここには2つの利点があります。Symfonyプロジェクトの任意のコンポーネントを置き換えることができることと、Symfony以外のプロジェクトの任意のSymfonyコンポーネントを取得して使用できることです。 symfonyコンポーネントは優れたコード例として役立ち、多くの場所で使用されています オープンソースプロジェクト Drupal、phpBB、Codeceptionなど。実際、Laravel自体は14以上のSymfonyコンポーネントを使用しています。したがって、Symfonyを理解すると、他のプロジェクトで作業するときに多くの利点が得られます。
どちらのフレームワークにも、インストーラーとラッパーが付属しています。 PHP組み込みWebサーバー 。
symfonyのインストールは以下のように簡単です:
# Downloading Symfony installer sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony # Granting permissions to execute installer sudo chmod a+x /usr/local/bin/symfony # Creating new Symfony project symfony new symfony_project # Launching built-in server cd symfony_project/ && php bin/console server:start
それでおしまい! SymfonyのインストールはURL http://localhost:8000
で入手できます。
LaravelのインストールプロセスはSymfonyの場合とほぼ同じで簡単です。唯一の違いは、Composerを介してLaravelのインストーラーをインストールすることです。
# Downloading Laravel installer using Composer composer global require 'laravel/installer' # Creating new Laravel project laravel new laravel_project # Launching built-in server cd laravel_project/ && php artisan serve
これでhttp://localhost:8000
にアクセスできますLaravelのインストールを確認してください。
注意: LaravelとSymfonyはどちらもデフォルトで同じローカルホストポート(8000)で実行されるため、これらのデフォルトインスタンスを同時に実行することはできません。 php bin/console server:stop
を実行してSymfonyサーバーを停止することを忘れないでくださいLaravelサーバーを起動する前に。
これらは基本的なインストールの例です。ローカルドメインでプロジェクトを構成したり、一度に複数のプロジェクトを実行したりできるなど、より高度な使用例の場合、両方のフレームワークにVagrantボックスが用意されています。
symfonyはその設定を指定するための構文としてYAMLを使用します。デフォルト設定はapp/config/config.yml
にありますファイルであり、次の例のようになります。
imports: - { resource: parameters.yml } - { resource: security.yml } - { resource: services.yml } framework: secret: '%secret%' router: { resource: '%kernel.root_dir%/config/routing.yml' } # ... # Twig Configuration twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' # ...
環境固有の構成を作成するには、ファイルapp/config/config_ENV.yml
を作成します。基本的な設定パラメータが含まれています。これがconfig_dev.yml
の例です開発環境用のファイル:
imports: - { resource: config.yml } # ... web_profiler: toolbar: true # ...
この例では、web_profiler
をオンにします開発環境専用のsymfonyツール。このツールは、ブラウザウィンドウでアプリケーションをデバッグおよびプロファイリングするのに役立ちます。
構成ファイルでは、%secret%
にも気付くことができます。建設。これにより、環境固有の変数を個別のparameters.yml
に配置できます。ファイル。このファイルはすべてのマシンで一意である可能性があり、バージョン管理下で保存されません。バージョン管理のために、特別なparameters.yml.dist
があります。 parameters.yml
のテンプレートであるファイルファイル。
これがparameters.yml
の例ですファイル:
parameters: database_host: 127.0.0.1 database_port: null database_name: symfony database_user: root database_password: null secret: f6b16aea89dc8e4bec811dea7c22d9f0e55593af
Laravelの構成はSymfonyの構成とは大きく異なります。共通しているのは、バージョン管理下に保存されていないファイル(Laravelの場合は.env
)とこのファイルを生成するためのテンプレート(.env.example
)の両方を使用していることだけです。このファイルには、次の例のように、キーと値のリストがあります。
APP_ENV=local APP_KEY=base64:Qm8mIaur5AygPDoOrU+IKecMLWgmcfOjKJItb7Im3Jk= APP_DEBUG=true APP_LOG_LEVEL=debug APP_URL=http://localhost
Symfony YAMLファイルと同様に、Laravel用のこれも人間が読める形式できれいに見えます。さらに.env.testing
を作成できますPHPUnitテストの実行時に使用されるファイル。
アプリケーション構成は.php
に保存されますconfig
内のファイルディレクトリ。基本設定はapp.php
に保存されますファイルおよびコンポーネント固有の構成は.php
に保存されますファイル(例:cache.php
またはmail.php
)。これがconfig/app.php
の例ですファイル:
'Laravel', 'env' => env('APP_ENV', 'production'), 'debug' => env('APP_DEBUG', false), 'url' => env('APP_URL', 'http://localhost'), 'timezone' => 'UTC', 'locale' => 'en', // ... ];
Symfonyのアプリケーション構成メカニズムを使用すると、環境ごとに異なるファイルを作成できます。さらに、YAML構成に複雑なPHPロジックを挿入することを防ぎます。
ただし、Laravelが使用しているデフォルトのPHP構成構文の方が快適であり、YAML構文を学ぶ必要はありません。
一般に、バックエンドWebアプリケーションには、各要求を読み取り、要求の内容に応じて応答を作成するという1つの主要な責任があります。コントローラーは、アプリケーションメソッドを呼び出すことによって要求を応答に変換する役割を担うクラスですが、ルーターは、特定の要求に対して実行する必要があるコントローラークラスとメソッドを検出するのに役立つメカニズムです。
/posts/{id}
からリクエストされたブログ投稿ページを表示するコントローラーを作成しましょうルート。
コントローラ
Post::findOrFail($id)]); } }
ルーター
Route::get('/posts/{id}', ' [email protected] ');
GET
のルートを定義しましたリクエスト。 /posts/{id}
に一致するURIを持つすべてのリクエストBlogController
を実行しますコントローラのshow
メソッドであり、パラメータid
を渡します。その方法に。コントローラで、モデルのオブジェクトを見つけようとしていますPOST
渡されたid
で、Laravelヘルパーを呼び出しますview()
ページをレンダリングします。
SymfonyではexampleController
少し大きいです:
getDoctrine()->getRepository('BlogBundle:Post'); $post = $repository->find($id); if ($post === null) { throw $this->createNotFoundException(); } return $this->render('BlogBundle:Post:show.html.twig', ['post'=>$post]); } }
すでに含まれていることがわかります@Route('/posts/{id}”)
アノテーションに含まれているので、コントローラーをrouting.yml
に含める必要があります。構成ファイル:
blog: resource: '@BlogBundle/Controller/' type: annotation prefix: /
ステップバイステップのロジックは、Laravelの場合と同じです。
この段階では、LaravelはSymfonyよりもはるかに優れていると思うかもしれません。これは最初は真実です。開始するのがずっと良くて簡単に見えます。ただし、実際のアプリケーションでは、コントローラーからDoctrineを呼び出すべきではありません。代わりに、投稿を見つけたり投げたりしようとするサービスを呼び出す必要があります HTTP404例外 。
Laravelにはと呼ばれるテンプレートエンジンが付属しています 刃 とSymfonyは 小枝 。両方のテンプレートエンジンは、2つの主要な機能を実装しています。
どちらの機能でも、オーバーライド可能なセクションを含む基本テンプレートと、それらのセクションの値を埋める子テンプレートを定義できます。
ブログ投稿ページの例をもう一度考えてみましょう。
// base.blade.php @section('page-title') Welcome to blog! @show {% block content %}{% endblock %} // show.html.twig {% extends '@Blog/base.html.twig' %} {% block page_title %}Post {{ post.title }} - read this and more in our blog.{% endblock %} {% block title %}{{ post.title }}{% endblock %} {% block content %} {{ post.content }} {% endblock %}
構造的に、BladeテンプレートとTwigテンプレートは非常に似ています。どちらもテンプレートをPHPコードに生成して高速に動作し、if
などの制御構造を実装します。ステートメントとループ。両方のエンジンが持つ最も重要な機能は、デフォルトで出力をエスケープすることです。これは、XSS攻撃の防止に役立ちます。
構文は別として、主な違いは、BladeではPHPコードをテンプレートに直接挿入できますが、Twigでは挿入できないことです。代わりに、Twigではフィルターを使用できます。
たとえば、文字列を大文字にする場合、Bladeで次のように指定します。
{{ ucfirst('welcome friend') }}
一方、Twigでは、次のことを行います。
{capitalize }
Bladeでは、一部の機能を拡張する方が簡単ですが、Twigではテンプレートに直接PHPコードを含めることはできません。
アプリケーションにはさまざまなサービスとコンポーネントがあり、さまざまな相互依存関係があります。作成されたオブジェクトとその依存関係に関するすべての情報を何らかの方法で保存する必要があります。
これが次のコンポーネントです- サービスコンテナ 。これは、要求されたサービスを作成し、作成されたオブジェクトとその依存関係に関する情報を格納するPHPオブジェクトです。
次の例を考えてみましょう。クラスを作成していますPostService
新しいブログ投稿の作成を担当するメソッドを実装します。このクラスは、他の2つのサービスに依存しています。PostRepository
はデータベースに情報を保存する役割を果たし、SubscriberNotifier
はサブスクライブしたユーザーに新しい投稿について通知する役割を果たします。これを機能させるには、これら2つのサービスをPostService
のコンストラクター引数として渡す必要があります。または、言い換えると、これらの依存関係を注入する必要があります。
契約率計算機にフルタイム
まず、サンプルサービスを定義しましょう。
repository = $repository; $this->notifier = $notifier; } public function create(Post $post) { $this->repository->persist($post); $this->notifier->notifyCreate($post); } }
次は、依存性注入の構成です。
# src/BlogBundle/Resources/config/services.yml services: # Our main service blog.post_service: class: BlogBundleServicePostService arguments: ['@blog.post_repository', '@blog.subscriber_notifier'] # SubscriberNotifier service. It could also have its own dependencies, for example, mailer class. blog.subscriber_notifier: class: BlogBundleServiceSubscriberNotifier # Repository. Don't dive deep into it's configuration, it is not a subject now blog.post_repository: class: BlogBundleRepositoryPostRepository factory: 'doctrine.orm.default_entity_manager:getRepository' arguments: - BlogBundleEntityPost
これで、サービスコンテナオブジェクトからコード内のどこにでもポストサービスをリクエストできます。たとえば、コントローラーでは次のようになります。
// Controller file. $post variable defined below $this->get('blog.post_service')->create($post);
サービスコンテナは優れたコンポーネントであり、次のアプリケーションを構築するのに役立ちます 固体 設計原則。
関連: symfonyコンポーネントによる真の依存性注入 Laravelの依存性注入の例
Laravelで依存関係を管理する方がはるかに簡単です。同じ例を考えてみましょう:
repository = $repository; $this->notifier = $notifier; } public function create(Post $post) { $this->repository->persist($post); $this->notifier->notifyCreate($post); } }
Laravelの美しさがここにあります- 依存関係の構成を作成する必要はありません 。 Laravelは依存関係を自動的にスキャンしてPostService
を探しますコンストラクターの引数の型で、それらを自動的に解決します。
コントローラメソッドでインジェクションを使用してPostService
を使用することもできますメソッド引数で「型ヒント」することにより、次のようになります。
'Title', 'content' => 'Content']); $service->create($post); return redirect('/posts/'.$post->id); } }
依存性注入:SymfonyとLaravel
Laravelの自動検出はうまく機能します。 symfonyには「 オートワイヤー 」はデフォルトでオフになっており、autowire: true
を追加することでオンにできます。依存関係の構成に追加しますが、いくつかの構成が必要です。 Laravelの方法はもっと簡単です。
オブジェクトリレーショナルマッピング(ORM)
データベースを操作するために、両方のフレームワークにはオブジェクトリレーショナルマッピング(ORM)機能が付属しています。 ORMは、データベースのレコードをコード内のオブジェクトにマップします。これを行うには、データベース内の各レコードタイプ(または各テーブル)のモデルを作成する必要があります。
symfonyはサードパーティのプロジェクトを使用しています 教義 Laravelが独自のライブラリを使用している間、データベースと対話するために 雄弁 。
EloquentORMは ActiveRecordパターン データベースを操作します。このパターンでは、各モデルはデータベースへの接続を認識しており、データベースと対話できます。たとえば、データをデータベースに保存したり、レコードを更新または削除したりできます。
Doctrineは データマッパーパターン 、モデルはデータベースについて何も知りません。彼らはデータ自体だけを知っています。特別な個別のレイヤーEntityManager
は、モデルとデータベース間の相互作用に関するすべての情報を格納し、すべての操作を処理します。
違いを理解するために例を見てみましょう。モデルにプライマリid
があるとします。キー、タイトル、コンテンツ、および作成者。ザ・ 投稿 テーブルには作成者id
のみが格納されるため、との関係を作成する必要があります ユーザー テーブル。
教義
モデルを定義することから始めましょう:
ここでは、モデルマッピング情報を作成し、ヘルパーを使用してメソッドスタブを生成できるようになりました。
php bin/console doctrine:generate:entities BlogBundle
次に、リポジトリ後のメソッドを定義します。
getEntityManager()->persist($post); $this->getEntityManager()->flush(); } /** * Search posts with given author's name * * @param string $name * @return array */ public function findByAuthorName($name) { return $this->createQueryBuilder('posts') ->select('posts') ->join('posts.author', 'author') ->where('author.name = :name') ->setParameter('name', $name) ->getQuery() ->getResult(); } }
これで、これらのメソッドをサービスから、またはたとえばPostController
から呼び出すことができます。
// To search for posts $posts = $this->getDoctrine()->getRepository('BlogBundle:Post')->findByAuthorName('Karim'); // To save new post in database $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post);
雄弁
ザ・ ユーザー モデルはLaravelに同梱されており、デフォルトで定義されているため、1つのモデルを定義するだけで済みます。 役職 。
belongsTo('AppUser', 'author_id'); } }
モデルについては以上です。 Eloquentでは、データベーステーブル構造に基づいて動的にモデルプロパティを構築するため、モデルプロパティを定義する必要はありません。新しい投稿を保存するには$post
データベースに、次の呼び出しを行う必要があります(たとえば、コントローラーから)。
$post->save();
特定の名前の作成者によるすべての投稿を検索するには、その名前のユーザーを検索して、すべてのユーザーの投稿をリクエストするのが最善の方法です。
$posts = Post::whereHas('author', function ($q) { $q->where('name', 'Karim'); })->get();
ORM:Symfony vs. Laravel
ORMに関しては、Eloquentははるかに友好的に見えます PHP開発者 Doctrineよりも習得が容易です。
イベントディスパッチャーとミドルウェア

フレームワークについて理解する最も重要なことの1つは、そのライフサイクルです。
symfonyとイベントディスパッチャー
リクエストをレスポンスに変換するために、SymfonyはEventDispatcherを使用します。その結果、さまざまなライフサイクルイベントと特別なイベントリスナーを起動して、これらのイベントを処理します。最初は、kernel.request
をディスパッチしますリクエスト情報を含むイベント。このイベントの主なデフォルトリスナーはRouterListener
です。これは、ルーターコンポーネントを呼び出して、現在の要求に適したルートルールを見つけます。この後、他のイベントが段階的に実行されます。典型的なイベントリスナーは、セキュリティチェック、CSRFトークン検証、およびロギングプロセスです。リクエストのライフサイクルにいくつかの機能を追加する場合は、カスタムEventListener
を作成する必要があります。必要なイベントに登録します。
Laravelとミドルウェア
Laravelは別のソリューションを使用しています:ミドルウェア。ミドルウェアをタマネギと比較するのが好きです。アプリケーションには特定のレイヤーがあり、リクエストはコントローラーに戻る途中でこれらのレイヤーを通過します。したがって、アプリケーションロジックを拡張し、リクエストのライフサイクルにいくつかの機能を追加する場合は、ミドルウェアリストにレイヤーを追加する必要があり、Laravelがそれを実行します。
REST API
ブログ投稿を管理するための基本的なCRUDの例を作成してみましょう。
- 作成-
POST /posts/
- 読む-
GET /posts/{id}
- 更新-
PATCH /posts/{id}
- 削除-
DELETE /posts/{id}
SymfonyのRESTAPI
Symfonyには、REST APIをすばやく作成するための簡単なソリューションはありませんが、優れたサードパーティバンドルがありますFOSRestBundle
およびJMSSerializerBundle
。
FOSRestBundle
を使用した最小限の作業例を考えてみましょう。およびJMSSerializerBundle
。それらをインストールしてAppKernel
でオンにした後、JSON形式を使用し、これをURLリクエストに含める必要がないことをバンドル構成で設定できます。
#app/config/config.yml fos_rest: routing_loader: default_format: json include_format: false
ルーティング構成では、このコントローラーがRESTリソースを実装するように指定する必要があります。
#app/config/routing.yml blog: resource: BlogBundleControllerPostController type: rest
前の例では、リポジトリにpersistメソッドを実装しました。次に、削除メソッドを追加する必要があります。
// src/BlogBundle/Repository/PostRepository.php public function delete(Post $post) { $this->getEntityManager()->remove($post); $this->getEntityManager()->flush(); }
次に、を作成する必要があります フォームクラス 入力要求を受け入れ、それらをモデルにマップします。 CLIヘルパーを使用してこれを行うことができます。
php bin/console doctrine:generate:form BlogBundle:Post
次のコードで生成されたフォームタイプを受け取ります。
add('title')->add('content'); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => 'BlogBundleEntityPost', 'csrf_protection' => false ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'post'; } }
それでは、コントローラーを実装しましょう。
注意: 私がお見せするコードは完璧ではありません。一部の設計原則に違反していますが、簡単にリファクタリングできます。主な目的は、各メソッドを実装する方法を段階的に示すことです。
getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post === null) { $view->setStatusCode(Response::HTTP_NOT_FOUND); } else { $view->setData(['post' => $post]); } return $this->handleView($view); } /** * @param Request $request * @return Response */ public function postPostAction(Request $request) { $view = new View(null, Response::HTTP_BAD_REQUEST); $post = new Post; $form = $this->createForm(PostType::class, $post, ['method' => $request->getMethod()]); $form->handleRequest($request); if ($form->isValid()) { $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post); $view->setStatusCode(Response::HTTP_CREATED); $postUrl = $this->generateUrl('get_post', ['id' => $post->getId()], UrlGeneratorInterface::ABSOLUTE_URL); $view->setHeader('Location', $postUrl); } else { $view->setData($form->getErrors()); } return $this->handleView($view); } /** * @param $id * @param Request $request * @return Response */ public function patchPostAction($id, Request $request) { $view = new View(null, Response::HTTP_BAD_REQUEST); $post = $this->getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post === null) { $view->setStatusCode(Response::HTTP_NOT_FOUND); } else { $form = $this->createForm(PostType::class, $post, ['method' => $request->getMethod()]); $form->handleRequest($request); if ($form->isValid()) { $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post); $view->setStatusCode(Response::HTTP_NO_CONTENT); $postUrl = $this->generateUrl('get_post', ['id' => $post->getId()], UrlGeneratorInterface::ABSOLUTE_URL); $view->setHeader('Location', $postUrl); } else { $view->setData($form->getErrors()); } } return $this->handleView($view); } /** * @param $id * @return Response */ public function deletePostAction($id) { $view = new View(null, Response::HTTP_NOT_FOUND); $post = $this->getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post !== null) { $this->getDoctrine()->getRepository('BlogBundle:Post')->delete($post); $view->setStatusCode(Response::HTTP_NO_CONTENT); } return $this->handleView($view); } }
FOSRestBundle
を使用すると、メソッドごとにルートを宣言する必要はありません。コントローラのメソッド名とJMSSerializerBundle
の規則に従うだけです。モデルを自動的にJSONに変換します。
LaravelのRESTAPI
まず、ルートを定義する必要があります。 API
でこれを行うことができます一部のデフォルトのミドルウェアコンポーネントをオフにし、他のコンポーネントをオンにするルートルールのセクション。 API
セクションはroutes/api.php
にありますファイル。
モデルでは、$fillable
を定義する必要がありますモデルのcreateメソッドとupdateメソッドで変数を渡すプロパティ:
次に、コントローラーを定義しましょう。
get('post')); return response(null, Response::HTTP_CREATED, ['Location'=>'/posts/'.$post->id]); } public function update(Post $post, Request $request) { $post->update($request->get('post')); return response(null, Response::HTTP_NO_CONTENT, ['Location'=>'/posts/'.$post->id]); } public function destroy(Post $post) { $post->delete(); return response(null, Response::HTTP_NO_CONTENT); } }
Symfonyでは、エラーをJSONでラップするFosRestBundle
を使用しています。 Laravelでは、自分で行う必要があります。 JSONリクエストを予期するためのJSONエラーを返すには、Exceptionハンドラーのrenderメソッドを更新する必要があります。
expectsJson()) { $status = 400; if ($this->isHttpException($exception)) { $status = $exception->getStatusCode(); } elseif ($exception instanceof ModelNotFoundException) { $status = 404; } $response = ['message' => $exception->getMessage(), 'code' => $exception->getCode()]; return response()->json($response, $status); } return parent::render($request, $exception); } // ... }
REST API:SymfonyとLaravel
ご覧のとおり、典型的なREST APIの場合、LaravelはSymfonyよりもはるかに単純です。
勝者を選ぶ:SymfonyまたはLaravel?
LaravelとSymfonyの間に明確な勝者はありません。すべてが最終的な目標に依存するためです。
Laravelは、次の場合に適しています。
- 習得が簡単で、構文がシンプルで教材が優れているため、これはフレームワークを初めて体験するものです。
- スタートアップ製品を構築し、仮説を確認します。これは、迅速なアプリケーション開発と Laravel開発者 見つけるのは簡単です。
次の場合、symfonyが最適なオプションです。
- 非常にスケーラブルで、保守が容易で、適切に構造化されているため、複雑なエンタープライズアプリケーションを構築しています。
- Symfonyは今後6年間のリリース計画を予測できるため、大規模な長期プロジェクトの移行を構築しているため、予期しない事態が発生する可能性は低くなります。