SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

軽量PHPフレームワークSlimを習得しよう

Slimのコンテナ機能を使ってみよう

軽量PHPフレームワークSlimを習得しよう 第5回


コンテナの仕組みに関する少し難しい話

 前節で、コンテナの利用方法に関する基本の解説は終わりです。ここでは、このコンテナの仕組みを解説していきましょう。といっても、本格的に解説するとなると紙面が足りませんし、不要な読者もいらっしゃるでしょう。そこで、ポイントをかいつまんで解説します。それでも少し難しい話になるかもしれませんが、了承ください。

配列アクセスの謎

 まず、リスト1の(2)から解説していきます。(1)でAppクラスから取得したコンテナ本体である$containerの実態は、\Slim\Containerクラスです。配列ではありません。それなのに、(2)でインスタンス生成関数を登録するのに配列アクセスのような方法をとっています。

 これは、\Slim\Containerクラス(より正確には\Slim\Containerクラスの親クラスに当たる\Pimple\Containerクラス)がArrayAccessインターフェースを実装しているからです。

 ArrayAccessインターフェースはPHPの定義済みインターフェースであり、クラスへのアクセスを配列のように扱えるものです。このインターフェースを実装しているおかげで、以下の記述が可能となっています。

$container["view"] = …

コンテナクラスからインスタンスを取得する別の記述

 コンテナクラスがArrayAccessインターフェースを実装しているということは、コンテナからインスタンスを取得する記述も配列アクセスのように記述できます。例えば、リスト2の(1)は以下のように記述しても問題なく動作します。

$view = $this["view"];

 さらに、以下のような記述も可能です。

$view = $this->view;

 これは、\Slim\Containerクラスがマジックメソッド__get()※を実装しており、そのため、インスタンス識別文字列をさもプロパティかのようにアクセスできるようにしてくれているからです。

※マジックメソッドに関しては、拙記事「PHPの「マジックメソッド」とは――「__set()」「__get()」「__invoke()」の使い方」を参考にしてください。

コンテナクラスはPSR-11を実装

 このように、コンテナは配列アクセスやプロパティのようなアクセス方法が可能なのに、なぜget()メソッドが存在するのでしょうか。それは、\Slim\ContainerクラスがPsr\Container\ContainerInterfaceインターフェースを実装しているからです。

 このPsr\Container\ContainerInterfaceは、PSR-11として定義されたインターフェースです。PSR(PHP Standards Recommendations)というのは、PHPのフレームワークやCMS、ツールの開発者が集まったグループ(PHP-FIG)で策定されている、PHPの標準規約のことです。

 そのNo.11として、こういったインスタンス生成を管理するコンテナに関するインターフェースが定義されています。このインターフェースには、表1のメソッドが2個定義されています。

表1:ContainerInterfaceに定義されたメソッド
メソッド 内容
get() 引数で渡されたインスタンス識別子でインスタンスを返すメソッド
has() 引数で渡されたインスタンス識別子が存在するかどうかを返すメソッド

 このことから、必要に応じて、例えば以下のようにインスタンス生成が可能かどうかを事前に確認するコードを記述することもできます。

if($this->has("view")) {

Slimでログを扱う

 ここまで紹介してきたコンテナですが、インスタンス生成をまとめておくことによってさらなる利点があります。それについて、ログの利用方法を題材に紹介したいと思います。そのために、Slimにおけるのログの扱いについて先に紹介します。

SlimではMonologを利用する

 実運用を想定したWebアプリではログへの書き出し処理は必須です。全ての不具合、障害はログを通じてでないと原因究明がほぼ不可能だからです。そのログへの書き出し機能をSlimは内包していません。

 そこで、別ライブラリを利用します。Slimで推奨しているのは、Monologの利用です。FirstSlimアプリにMonologを利用できるようにしていきましょう。

Monologパッケージの配置

 まず、ComposerでMonologパッケージを配置します。srcフォルダで以下のコマンドを実行してください。

composer require monolog/monolog

 すると、composer.jsonファイルとcomposer.lockファイルが更新され、必要なパッケージがダウンロードされます。特に問題なく処理が終了すれば、Monologの配置は完了しています。

Loggerインスタンスのコンテナ追加

 次に、Monologの本体クラスであるLoggerのインスタンスをアプリ全体で利用できるように、コンテナに追加しましょう。リスト3の太字のコードをindex.phpに追記してください。

[リスト3]firstslim/src/public/index.php
<?php
use Slim\App as App;
use Slim\Views\Twig;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
〜省略〜
$container["logger"] = function($container)  // (1)
{
	$logger = new Logger("firstslim");  // (2)
	$fileHandler = new StreamHandler("../../logs/app.log");  // (3)
	$logger->pushHandler($fileHandler);  // (4)
	return $logger;  // (5)
};
require_once("../routes.php");
〜省略〜

 リスト3の(2)~(4)が、Monologを利用するための定型処理となります。まず、(2)のようにMonologの本体クラスであるLoggerクラスをnewします。その際、引数としてログでのアプリの識別文字列を渡します。

 そのLoggerクラス自身は、ログへの書き出し機能を内包していません。ログへの書き出し機能はそれ専用のクラス(これをハンドラといいます)に任せます。つまり分業です。

 そのハンドラクラスのうち、ファイルへの書き出しを行ってくれるクラスがStreamHandlerクラスです。そのStreamHandlerクラスをnewしているのがリスト3の(3)です。その際、ファイルパスを引数として渡します。ここでは、firstslimフォルダ直下のlogsフォルダにapp.logというファイル名で書き出すように指定しています。

 最後に、LoggerクラスのpushHandler()メソッドを使って(3)で生成したハンドラインスタンスを登録します。それがリスト3の(4)です。

 ここまでで、ログの書き出しの準備が整ったLoggerインスタンスが生成できました。それを(5)のようにリターンする無名関数をコンテナに登録します。それが(1)です。これで、コンテナからいつでもログへの書き出し準備が整ったLoogerインスタンスを取得できます。

Loggerを利用するコードの記述

 最後に、ルーティング登録ファイルであるroutes5.phpにログへの書き出し実験を行うコードを記述しましょう。リスト4の内容を追記してください。

[リスト4]firstslim/src/routes5.php
<?php
〜省略〜
$app->any("/no5/writeToLog",
	function(Request $request, Response $response, array $args): void
	{
		$logger = $this->get("logger");  // (1)
		$logger->info("ログに書き出しました。");  // (2)
		print("<h1>ログへの書き出し実験</h1>");
	}
);

 追記が終了したら、以下のURLにアクセスしてください。

  • http://localhost/firstslim/src/public/no5/writeToLog

 ただし、念のためにあらかじめfirstslimフォルダ内にlogsフォルダを作成しておきましょう。さらに、Macの場合は、このフォルダに以下のコマンドで書き込み権限を与えておきましょう。でないとエラーとなります。

chmod 777 logs/

 URLにアクセスすると、ブラウザには「ログへの書き出し実験」と表示され、logsフォルダ内にapp.logが生成されるはずです。以下の内容が記述されていれば、成功です。

[2019-05-28 09:05:26] firstslim.INFO: ログに書き出しました。 [] []

 さて、リスト4のコードを確認しておきましょう。まず、コンテナからLoggerインスタンスを取得しているのが、(1)です。そのLoggerインスタンスのメソッドinfo()を使ってログへの書き出しを行っているのが(2)です。

 ログに何かを記述する場合、その記述する内容の重要度がおのずと変わってきます。この重要度のことを「ログレベル」といい、Monologでは8段階あります。そのログレベルそれぞれに対応したメソッドがLoggerクラスには用意されており、そのメソッドを実行することで、ログへの書き出しを行ってくれます。8段階のログレベルを表2にまとめておきます。

表2:Monologで定義されたログレベル
ログレベル 対応メソッド 内容   
DEBUG debug()  デバッグ用の詳細情報
INFO  info()  一般的な情報
NOTICE notice()  注意が必要な情報
WARNING warning()  エラーとまではいえないが例外的な動作の情報
ERROR  error()  すぐに対応する必要はないが、実行エラー情報
CRITICAL critical()  重大なエラー情報
ALERT alert()  すぐに対応が必要なエラー情報
EMERGENCY emergency()  システムが利用できないなどの緊急情報

次のページ
コンテナとDI

この記事は参考になりましたか?

軽量PHPフレームワークSlimを習得しよう連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11617 2019/07/11 11:22

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー