ググったら似たような記事は結構出てくる。
頭の良い人はLaravelのIlluminate\Container\Containerをいっぱいみてください。
<?php
//従業員の抽象
interface EmployeeInterface
{
public function work() :string;
}
class Engineer implements EmployeeInterface
{
public function work() :string
{
return "create products";
}
}
class Salesman implements EmployeeInterface
{
public function work() :string
{
return "sale products";
}
}
// 会社クラス
class Company {
private $employee;
public function __construct(EmployeeInterface $employee)
{
$this->employee = $employee;
}
public function makeEmployeeWork()
{
return $this->employee->work();
}
}
//コンテナ
class Container {
//バインドした具象の配列
private $binding;
//抽象クラスと生成した具体クラスとをセットで登録
public function bind($abstract, $concrete)
{
$this->binding[$abstract] = new $concrete;
}
//コンテナを経由してDIしながらインスタンスを生成する
public function make($className) :object
{
$abstracts = $this->getAbstract($className);
$concretes = [];
foreach($abstracts as $abstract){
$concretes[] = $this->binding[$abstract];
}
$class = new $className(...$concretes);
return $class;
}
//コンテナ経由で生成するインスタンスのコンストラクタの引数のinterfaceを取得
private function getAbstract($className) :array
{
$reflectionClass = new ReflectionClass($className);
$reflectionMethod = $reflectionClass->getConstructor();
$reflectionParameters = $reflectionMethod->getParameters();
//ReflectionParameterクラスを取得
$abstracts = [];
foreach($reflectionParameters as $parameter){
$abstracts[] = $parameter->getClass()->getName();
//抽象クラス名取得
}
return $abstracts;
}
}
// コンテナを操るクラス。別にコンテナをnewしてもいいけどLaravelを模倣して作っといた。
class Provider
{
public $app; //コンテナ
public function __construct($container){
$this->app = $container;
}
}
class Application
{
public $provider;
public function __construct()
{
ini_set('display_errors', "On");
$this->provider = new Provider(new Container());
//プロバイダー生成
}
public function freeZone(){
// $this->provider->app->bind(EmployeeInterface::class, Engineer::class);
$this->provider->app->bind(EmployeeInterface::class, Salesman::class);
//具体クラスを変更するときはバインドを変更するのみ
$company = $this->provider->app->make("Company");
//コンテナ経由でcompanyインスタンスを生成する
echo $company->makeEmployeeWork();
//労働させる
}
}
(new Application())->freeZone();
//コード実行
?>