如果您想从数据库中获取单个对象,PDO非常有用:
$obj = $handle->fetchAll(PDO::FETCH_CLASS, $obj_name);
如果您希望在一行中返回多个类类型(例如:在进行JOIN时),PDO的帮助不大:
$handle->fetchAll(PDO::FETCH_ASSOC);
...followed by some data mapping on the resulting array。很好 - 除了我想出来的每一种方法看起来都很糟糕。
我的问题是:如果该数组的内容可能反映所有,没有,某些或多于所需的内容,那么如何以优雅,健壮的方式实例化来自同一数组的多个对象类?
给定PDO从数据库$vars = ('a' => 1, 'b' => 2, 'c' => 3, 'x' => 7, 'y' => 8, 'z' => 9)
返回的数组,构造对象ABC
(需要$a
,$b
和$c)
以及{{1} (XYZ
,$x
,$y
)没有太多的复制和粘贴。
$z
(许多样板代码/复制粘贴/要求实例化代码已按正确顺序准备好所有变量)
class ABC {
private $a, $b, $c;
function __construct ($a = null, $b = null, $c = null) {
$this->$a = $a ? $a : $this->a;
$this->$b = $b ? $b : $this->b;
...
(更好,但如果$ vars中不存在数组键,则会抱怨。当然,我们可以使用isset()但这会使样板问题更严重)
function ABCFactory($vars = array()) {
return new ABC($vars['a'], $vars['b']....
(它有效,它很整洁,它很整洁,它很容易重复使用,它会反映我添加的任何新的类变量......但是它已经... eval(),这给了我噩梦!:])
dockeryZ 暗示了它,但 mleko 提供了答案。我之前没有听说过变量变量,但它们正是我想要的。我终于去了:
foreach ($vars AS $key => $value) {
eval("if (isset(\$key) && \$value) \$this->$key = '$value';");
}
然而,未来发现这一点的任何人都应该牢记 Johan Perez 的答案,不要将此片段用作构造函数中的快捷方式...特别是如果输入数组来了来自用户的GET或POST参数!
答案 0 :(得分:1)
你去吧
<?php
class Name {
public function __construct($data) {
foreach($data as $key=>$val){
$this->{$key}=$val;
}
}
}
答案 1 :(得分:1)
就个人而言,我永远不会使用构造函数来设置对象的属性。原因是封装远不止Getters和Setters。像这样做封装:
class Person {
private $birthDate;
private $parents;
public function getBirthDate(){
return $this->birthDate;
}
public function setBirthDate($birthDate){
$this->birthDate = $birthDate;
}
public function getParents(){
return $this->parents;
}
public function setParents($parents){
$this->parents = $parents;
}
}
甚至比根本不进行封装更糟糕,因为您已经避免了封装本身的主要目的:数据的完整性。在上面的例子中,生日可能很容易,不是日期,也不是未来的某个日期。而你的父母甚至不可能是一群母亲和父亲(或父亲和父亲或母亲和母亲......)。你应该注意一些事情。
在您的示例中,在构造函数中,您只是检查不是null,但是您没有检查任何其他内容。这可能会使您的对象中的某些数据无效,并且在您打算使用它之前就已经注意到了。在调试时,这可能很容易让您花费数小时才能找到问题。
对我来说,正确的方法是创建一个静态方法,该方法返回使用正确的getter和setter映射的对象的实例。像这样:
class Person {
private $birthDate;
private $parents;
public function getBirthDate(){
if (isset($this->birthDate) {
return $this->birthDate;
else {
return new DateTime('NOW');
}
}
public function setBirthDate($birthDate){
if ($birthDate instanceof DateTime){
$this->birthDate = $birthDate;
} else {
throw new InvalidArgumentException("Person::birthDate should be an instance of DateTime");
}
}
public function getParents(){
if (isset($this->parents) {
return $this->parents;
else {
return new array("father" => null, "mother" => null);
}
}
public function setParents($parents){
if (is_array($parents) && array_keys($parents) == array("father", "mother")){
if ($parents["father"] instanceof Person && $parents["mother"] instanceof Person){
$this->parents = $parents;
} else {
throw new InvalidArgumentException("Father and Mother should be instances of Person class.");
}
} else {
throw new Invalid ArgumentException("Person::parents should be an array and in must contain only ['father'] and ['mother'] keys.");
}
}
public static function createPersonFromPDO($pdoArray){
// Check here if $pdoArray is an array and it is a valid array.
$person = new Person();
foreach($pdoArray as $key => $value){
switch($key){
case "birthDate":
$person->setBirthDate($value);
break;
case "parents":
$person->setParents($value);
break;
}
}
return $person;
}
}