我有一些代码,用户可以通过数据库设置任意数量的数组元素。我是基于键名的鸭子打字函数,但并非所有的键名都是要调用的对象,我不能保证键可以是静态的顺序。代码类似于:
$arr = get_arr_from_db();
foreach($arr as $key => $val){
if($obj = new $key){
unset($arr[$key]);
$obj->give_data($arr);
break;
}
}
$obj->quack();
上述代码不起作用,因为$obj = new $key
将会死亡。在创建失败的对象时,有什么方法可以让上面的循环不受影响?
答案 0 :(得分:1)
您可以在尝试实例化之前使用class_exists()
,如果无法实例化,try / catch块也会捕获任何错误。
foreach($arr as $key => $val){
if(class_exists($key)){
try {
if($obj = new $key){
unset($arr[$key]);
if(method_exists($obj, 'give_data'){
$obj->give_data($arr);
}
break;
}
} catch(Exception $e) {
// do something with the exception
}
}
}
答案 1 :(得分:1)
使用serialize和unserialize会更直接,它将为您处理类初始化和类型检查。
E.g:
$person = new Person();
$person->firstname = 'Chuck';
$person->lastname = 'Jones';
$blob = serialize($person); // put blob in the database
如果您想遵循give_data()
方法(例如,您的类属性与数据库中的列名匹配),则应指定interface。接口可以保证您正在调用的类具有可用的unserialize方法,并且它的行为与您期望的一样(下面的示例使用工厂模式):
<?php
interface ArraySerializable
{
public static function createFromArray($array);
}
class Person implements ArraySerializable
{
public static function createFromArray($array)
{
$temp = new self();
$temp->firstname = $array['first_name'];
$temp->lastname = $array['last_name'];
return $temp;
}
}
然后你要测试class_implements()
$class_name = 'Person';
if (class_exists($class_name)
&& in_array('ArraySerializable', class_implements($class_name))
){
$person = $class_name::createFromArray(array(
'last_name' => 'Jones',
'first_name' => 'Chuck'
));
var_dump($person);
}
要在更多类中使用它,您只需为每个类实现ArraySerializable
接口。
如果您不想从头开始滚动,可以使用功能齐全的ORM(如Doctrine)来完全抽象数据库。
答案 2 :(得分:0)
最好使用Reflector类:
foreach($arr as $key => $val){
$reflection = new ReflectionClass($key);
if ($reflection->IsInstantiable()) {
unset($arr[$key]);
$obj = $reflection->newInstance();
$obj->give_data($arr);
break;
}
}