初めてのPHP ⑨。DIコンテナ、オートロードの使い方

初めてのPHP ⑨。DIコンテナ、オートロードの使い方
この記事はこんな悩みを解決します
  • DIコンテナって何?
  • オートロードを使ってみたい
  • PHPの勉強がしたい

DIコンテナやオートロードを使うことでアプリの柔軟性が高まり、開発がしやすくなります。PHPでの処理が一通りできるようになってきたのでファイルの中身を整理して行きましょう。

この記事を読むことでDIコンテナとオートロードの使い方がわかります。

初めてのPHP ⑨。DIコンテナ、オートロードの使い方

まずは復習をしていきましょう。

<?php

	$database = require 'core/bootstrap.php';

	require Router::load('routes.php')->direct(Request::uri(), Request::method());

?>

$databaseの中にcore/bootstrap.phpが入っています。
core/bootstrap.phpの詳細は下記の通りです。

<?php

$config = require 'config.php';
require 'core/Router.php';
require 'core/Request.php';
require 'core/database/Connection.php';
require 'core/database/Query.php';

return new Query(
	Connection::make($config['database'])
);

このままでも良いのですが、これだと$databaseの中に$configがあるので少し紛らわしくなります。
なので、$appの中にこの2つを作って行きたいと思います。

<?php

$app = [];

$app['$config'] = require 'config.php';
require 'core/Router.php';
require 'core/Request.php';
require 'core/database/Connection.php';
require 'core/database/Query.php';

$app['database'] = new Query(
	Connection::make($app['$config']['database'])
);

こんな感じでいいかと思います。
これで過去に$databaseと書いたところを$app[‘database’]と書けば動くはずです。

index.phpも若干の修正を行います。

// $database = require 'core/bootstrap.php';

require 'core/bootstrap.php';
// $databaseがいらないので削除

require Router::load('routes.php')->direct(Request::uri(), Request::method());

こっちの方がわかりやすいですよね。
ちなみに、これに対応するようにコントローラーのファイルも修正していきましょう。これまでのファイルを作っているなら下記の3つを修正する必要があります。

─── PHP-start
    ├── controllers.php  
     ├── comment.php
     ├── delete.php
       ├── index.view.php

// $databaseを$app['database']に修正していきましょう

DIコンテナを使ってみよう

こうした配列でも良いのですが、他のファイルから呼び出すときに使いにくいのでDI(Dependency Injection)コンテナを使っていきたいと思います。

DIコンテナといっても難しく捉える必要はなく$〜のようなインスタンスの中にnew 〜のようなオブジェクトを定義して取り扱いやすくしているだけです。

ピンとこないかもしれませんが、見ていきましょう。

bootstrap.phpにAppオブジェクトを使います

<?php
// $app = [];

require 'core/App.php'; //追加しています
require 'core/Router.php';
require 'core/Request.php';
require 'core/database/Connection.php';
require 'core/database/Query.php';

//$app['$config'] = require 'config.php';
↓
App::bind('config', require 'config.php');
//Appというクラスを作ってbindメソッドでconfigの中にconfig.phpを入れるようにしています。

// $app['database'] = new Query(
	Connection::make($app['$config']['database'])
);
↓
App::bind('database', new Query(
	Connection::make(App::get('config')['database'])
));
//databaseの中にnew Queryを入れています。
//また、getでAppクラスから必要なオブジェクトを取り出せるようにしています。

では、bindやgetメソッドを書いていきます。

App.phpを作成しbind、getメソッドを書きます

<?php

class App{
	protected static $registry = [];

	public static function bind($key, $value){
		static::$registry[$key] = $value;
	}
	public static function get($key){
		if(!array_key_exists($key, static::$registry)){
			throw new Exception("error");
		}
//$registryの中に$keyがなかったらエラーになるようにしています。
//$keyがあれば$keyに対応するオブジェクトを返します。
		return static::$registry[$key];
	}
}

Appオブジェクトのなかのdatabaseを引き出すことでQueryオブジェクトが使えるようになるので便利ですよね。

あとは再び下記のファイルについて修正します。

─── PHP-start
    ├── controllers.php  
     ├── comment.php
     ├── delete.php
       ├── index.view.php

// $app['database']をApp::get('database')に修正していきましょう

これで今までと同じように機能するかブラウザで確認します。

オートロードを使ってみよう

bootstrap.phpではたくさんのファイルをrequireしています。

require 'core/App.php';
require 'core/Router.php';
require 'core/Request.php';
require 'core/database/Connection.php';
require 'core/database/Query.php';

今後も開発を続けていくとファイル数が増えていくのでオートロードを使っていくと便利です。まずはComposerのサイトにアクセスしましょう。

Composerのダウンロード

ダウンロード画面に行き、下記の赤ワクのコマンドを全てTerminalに貼り付けます。

うまくインストールできたらcomposerと打つと下記のようなメッセージが出てきます。

mbp:PHP-start user$ composer
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.10.1 2020-03-13 20:34:27

Usage:
  command [options] [arguments]

Options:
 //以下省略

Conposerによるオートロードの設定

Composerを使う前にPHP_startの直下にcomposer.jsonを作り下記のように書きます。

{
	"autoload": {
		"classmap": [
			"./" //これでPHP_start全体のクラスファイルを認識するようになります。
		]
	}
}

準備ができたら、Terminalからcomposer installを唱えます。

mbp:PHP-start user$ composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Generating autoload files

これによりVenderフォルダが作られます。さらに、venderの中のcomposerフォルダの中にautoload_classmap.phpでオートロードされているファイルが確認できます。

<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'App' => $baseDir . '/core/App.php',
    'Connection' => $baseDir . '/core/database/Connection.php',
    'Query' => $baseDir . '/core/database/Query.php',
    'Request' => $baseDir . '/core/Request.php',
    'Router' => $baseDir . '/core/Router.php',
);

index.phpでオートロードしたファイルをrequireします

require 'vendor/autoload.php'; //追加

この1つを読み込めば全てのファイルがrequireできるようになっています。
そのため、bootstrap.phpを下記のようにしてもブラウザに変化がありません。

<?php
// requireを全て削除
// require 'core/App.php';
// require 'core/Router.php';
// require 'core/Request.php';
// require 'core/database/Connection.php';
// require 'core/database/Query.php';

App::bind('config', require 'config.php');

App::bind('database', new Query(
	Connection::make(App::get('config')['database'])
));

何か新たなファイルを作ったときには更新しましょう。

composer dump-autoload

このコマンドで自動的にファイルを読み込んでくれます。

まとめ

今回はDIコンテナとオートロードの使い方を紹介しました。

こうした機能を使いこなせるようになると開発が進みやすい環境を整えることができます。フレームワークを使っていくことを考えている方は理解しておきましょう。

関連記事