簡短的答案是,你根本無法確定一組參數是否允許構造函數無錯實例化。正如評論者在上面提到的那樣,無法確切知道某個類是否可以使用給定的參數列表進行實例化,因爲存在運行時注意事項,但實際上並未嘗試實例化。
但是,嘗試使用來從構造函數參數列表中實例化一個類。這種操作最明顯的用例是一個可配置的依賴注入容器(DIC)。不幸的是,這比OP建議的操作複雜得多。
我們需要爲提供的定義數組中的每個參數確定它是否與構造方法簽名中的指定類型提示匹配(如果方法簽名實際上具有類型提示)。另外,我們需要解決如何處理默認參數值。另外,爲了使我們的代碼具有任何實際的用途,我們需要提前指定「定義」來實例化一個類。對問題的複雜處理還將涉及一系列反射對象(緩存),以最大限度地減少反覆反映事件的性能影響。
另一個障礙是,沒有辦法來訪問一個反映方法參數的類型提示,而不調用其ReflectionParameter::getClass
方法,並隨後從返回的類名實例化一個反射類(如果返回null
帕拉姆沒有類型-暗示)。這是緩存生成的反射對於任何真實世界的用例變得特別重要。
下面的代碼是我自己的基於字符串的遞歸依賴注入容器的嚴格精簡版本。它是僞代碼和實際代碼的混合體(如果您希望免費代碼複製/粘貼,那麼您運氣不佳)。您將看到下面的代碼將「定義」數組的關聯數組鍵與構造函數簽名中的參數名稱進行匹配。
真實的代碼可以在相關的github project page找到。
class Provider {
private $definitions;
public function define($class, array $definition) {
$class = strtolower($class);
$this->definitions[$class] = $definition;
}
public function make($class, array $definition = null) {
$class = strtolower($class);
if (is_null($definition) && isset($this->definitions[$class])) {
$definition = $this->definitions[$class];
}
$reflClass = new ReflectionClass($class);
$instanceArgs = $this->buildNewInstanceArgs($reflClass);
return $reflClass->newInstanceArgs($instanceArgs);
}
private function buildNewInstanceArgs(
ReflectionClass $reflClass,
array $definition
) {
$instanceArgs = array();
$reflCtor = $reflClass->getConstructor();
// IF no constructor exists we're done and should just
// return a new instance of $class:
// return $this->make($reflClass->name);
// otherwise ...
$reflCtorParams = $reflCtor->getParameters();
foreach ($reflCtorParams as $ctorParam) {
if (isset($definition[$ctorParam->name])) {
$instanceArgs[] = $this->make($definition[$ctorParam->name]);
continue;
}
$typeHint = $this->getParameterTypeHint($ctorParam);
if ($typeHint && $this->isInstantiable($typeHint)) {
// The typehint is instantiable, go ahead and make a new
// instance of it
$instanceArgs[] = $this->make($typeHint);
} elseif ($typeHint) {
// The typehint is abstract or an interface. We can't
// proceed because we already know we don't have a
// definition telling us which class to instantiate
throw Exception;
} elseif ($ctorParam->isDefaultValueAvailable()) {
// No typehint, try to use the default parameter value
$instanceArgs[] = $ctorParam->getDefaultValue();
} else {
// If all else fails, try passing in a NULL or something
$instanceArgs[] = NULL;
}
}
return $instanceArgs;
}
private function getParameterTypeHint(ReflectionParameter $param) {
// ... see the note about retrieving parameter typehints
// in the exposition ...
}
private function isInstantiable($class) {
// determine if the class typehint is abstract/interface
// RTM on reflection for how to do this
}
}
它是PHP,當您使用Reflection時,很明顯它是PHP 5.如果您關注*特定PHP 5版本,請使用該PHP版本的標籤 - 但我沒有看到你需要你的問題。 - 你見過http://www.php.net/manual/en/reflectionfunctionabstract.getparameters.php和http://www.php.net/manual/en/class.reflectionparameter.php嗎? – hakre
@hakre很好,對於恢復您的編輯感到抱歉! – gremo
如果不執行代碼,您幾乎不知道實例化是否會成功。在那裏可能會有一個'if(rand())throw new Exception',這使得無需運行代碼就無法確定。 – deceze