學習php反射(2)——不用new方法例項化類
阿新 • • 發佈:2019-02-04
上一篇簡單介紹了 php 反射的幾個常見類的使用方法,但是用反射能做些什麼,你可能還是想象不到,
下面我稍微應用反射類來做點東西,大家知道例項化一個類需要用new
關鍵字,不用 new
可以嗎?答案是可以的,用反射就能實現:
首先建立一個檔案 student.php
:
<?php class Student { public $id; public $name; public function __construct($id,$name) { $this->id = $id; $this->name = $name; } public function study() { echo $this->name.' is learning.....'.PHP_EOL; } public function showBag(){ echo "My bag have ".$this->bag->all(); } }
另新建一個檔案run.php
<?php require 'student.php'; function make($class, $vars = []) { $ref = new ReflectionClass($class); if(!$ref->isInstantiable()) { throw new Exception("類{$class} 不存在"); } $constructor = $ref->getConstructor(); if(is_null($constructor)) { return new $class; } $params = $constructor->getParameters(); $resolveParams = []; foreach ($params as $key=>$value) { $name = $value->getName(); if(isset($vars[$name])) { $resolveParams[] = $vars[$name]; } else { $default = $value->isDefaultValueAvailable() ? $value->getDefaultValue() : null; if(is_null($default)) { if($value->getClass()) { $resolveParams[] = make($value->getClass()->getName(), $vars); } else { throw new Exception("{$name} 沒有傳值且沒有預設值。"); } } else { $resolveParams[] = $default; } } } return $ref->newInstanceArgs($resolveParams); }
run.php
中make
函式就是我們用來例項化類而編寫的函式,第一個引數傳入類名,第二個引數是類的建構函式需要傳入的引數資料。
根據 Student
的建構函式的引數不同有幾種情況:(以下程式碼,請按不同情況追加到
run.php 中執行)
情況一: 沒有提供 $name 的值
try {
$stu = make('Student', ['id' => 1]);
print_r($stu);
$stu->study();
} catch (Exception $e) {
echo $e->getMessage();
}
在建構函式中$name
Student
類,給 $name
提供一個預設值,這時候就不會報錯了。
情況二 提供了 $name 的值
try {
$stu = make('Student', ['id' => 1, 'name' => 'li']);
print_r($stu);
$stu->study();
} catch (Exception $e) {
echo $e->getMessage();
}
情況三,我們把 student.php
改一下
<?php
class Bag{
public function name(){
return "學生包".PHP_EOL;
}
}
class Student
{
public $id;
public $name;
public function __construct($id, $name="xxx", Bag $bag)
{
$this->id = $id;
$this->name = $name;
$this->bag = $bag;
}
public function study()
{
echo $this->name.' is learning.....'.PHP_EOL;
}
public function showBag(){
echo "My bag is ".$this->bag->name();
}
}
可以看到,給 Student
類加了一個引數$bag
,
型別 是 Bag
這時候執行一下
<?php
try {
$stu = make('Student', ['id' => 1, 'name' => 'li']);
print_r($stu);
$stu->study();
$stu->showBag();
} catch (Exception $e) {
echo $e->getMessage();
}
可以看到建構函式的第三個引數 $bag
,被自動例項化了,然後傳遞給了 Student
類的建構函式,這個部分很關鍵,這個地方可以用來實現依賴注入,我們不必在手動例項化物件了,我們可以根據引數的對應的類來自動例項化物件,從而實現類之間的解耦。如果你學過
Laravel的話,你應該對這個很熟悉了。
轉自:http://www.dahouduan.com/2017/08/22/php-reflection-2/