你不能在一个PHP类中放入两个具有唯一参数签名的__construct函数。我想这样做:

class Student 
{
   protected $id;
   protected $name;
   // etc.

   public function __construct($id){
       $this->id = $id;
      // other members are still uninitialized
   }

   public function __construct($row_from_database){
       $this->id = $row_from_database->id;
       $this->name = $row_from_database->name;
       // etc.
   }
}

PHP中最好的方法是什么?


当前回答

更现代的方法: 你把独立的类混合成一个,实体和数据水合。 对于你的案例,你应该有两个类:

class Student 
{
   protected $id;
   protected $name;
   // etc.
}
class StudentHydrator
{
   public function hydrate(Student $student, array $data){
      $student->setId($data['id']);
      if(isset($data['name')){
        $student->setName($data['name']);
      }
      // etc. Can be replaced with foreach
      return $student;
   }
}

//usage
$hydrator = new StudentHydrator();
$student = $hydrator->hydrate(new Student(), ['id'=>4]);
$student2 = $hydrator->hydrate(new Student(), $rowFromDB);

另外请注意,您应该使用doctrine或其他已经提供自动实体水合的ORM。 你应该使用依赖注入来跳过手动创建像StudentHydrator这样的对象。

其他回答

public function __construct() {
    $parameters = func_get_args();
    ...
}

$o = new MyClass('One', 'Two', 3);

现在$ parameters将是一个值为'One', 'Two', 3的数组。

编辑,

我可以加上

func_num_args()

会给出函数的参数个数。

PHP是一种动态语言,因此不能重载方法。你必须像这样检查参数的类型:

class Student 
{
   protected $id;
   protected $name;
   // etc.

   public function __construct($idOrRow){
    if(is_int($idOrRow))
    {
        $this->id = $idOrRow;
        // other members are still uninitialized
    }
    else if(is_array($idOrRow))
    {
       $this->id = $idOrRow->id;
       $this->name = $idOrRow->name;
       // etc.  
    }
}

另一种选择是像这样在构造函数中使用默认参数

class Student {

    private $id;
    private $name;
    //...

    public function __construct($id, $row=array()) {
        $this->id = $id;
        foreach($row as $key => $value) $this->$key = $value;
    }
}

这意味着你需要实例化一行像这样:$student = new student ($row['id'], $row),但保持你的构造函数漂亮和干净。

另一方面,如果你想利用多态性,那么你可以创建两个类,像这样:

class Student {

    public function __construct($row) {
         foreach($row as $key => $value) $this->$key = $value;
    }
}

class EmptyStudent extends Student {

    public function __construct($id) {
        parent::__construct(array('id' => $id));
    }
}

这里有一种优雅的方法。创建trait,在给定参数数量的情况下启用多个构造函数。你只需将参数的数量添加到函数名“__construct”中。所以一个参数是"__construct1",两个"__construct2"…等。

trait constructable
{
    public function __construct() 
    { 
        $a = func_get_args(); 
        $i = func_num_args(); 
        if (method_exists($this,$f='__construct'.$i)) { 
            call_user_func_array([$this,$f],$a); 
        } 
    } 
}

class a{
    use constructable;

    public $result;

    public function __construct1($a){
        $this->result = $a;
    }

    public function __construct2($a, $b){
        $this->result =  $a + $b;
    }
}

echo (new a(1))->result;    // 1
echo (new a(1,2))->result;  // 3

让我在这里加一粒沙子

我个人喜欢将构造函数作为返回类(对象)实例的静态函数添加。代码示例如下:

 class Person
 {
     private $name;
     private $email;

     public static function withName($name)
     {
         $person = new Person();
         $person->name = $name;

         return $person;
     }

     public static function withEmail($email)
     {
         $person = new Person();
         $person->email = $email;

         return $person;
     }
 }

注意,现在你可以像这样创建Person类的实例:

$person1 = Person::withName('Example');
$person2 = Person::withEmail('yo@mi_email.com');

我的代码来自:

http://alfonsojimenez.com/post/30377422731/multiple-constructors-in-php