你不能在一个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中最好的方法是什么?


当前回答

对于php7,我也比较了参数类型,你可以有两个具有相同数量的参数但不同类型的构造函数。

trait GenericConstructorOverloadTrait
{
    /**
     * @var array Constructors metadata
     */
    private static $constructorsCache;
    /**
     * Generic constructor
     * GenericConstructorOverloadTrait constructor.
     */
    public function __construct()
    {
        $params = func_get_args();
        $numParams = func_num_args();

        $finish = false;

        if(!self::$constructorsCache){
            $class = new \ReflectionClass($this);
            $constructors =  array_filter($class->getMethods(),
                function (\ReflectionMethod $method) {
                return preg_match("/\_\_construct[0-9]+/",$method->getName());
            });
            self::$constructorsCache = $constructors;
        }
        else{
            $constructors = self::$constructorsCache;
        }
        foreach($constructors as $constructor){
            $reflectionParams = $constructor->getParameters();
            if(count($reflectionParams) != $numParams){
                continue;
            }
            $matched = true;
            for($i=0; $i< $numParams; $i++){
                if($reflectionParams[$i]->hasType()){
                    $type = $reflectionParams[$i]->getType()->__toString();
                }
                if(
                    !(
                        !$reflectionParams[$i]->hasType() ||
                        ($reflectionParams[$i]->hasType() &&
                            is_object($params[$i]) &&
                            $params[$i] instanceof $type) ||
                        ($reflectionParams[$i]->hasType() &&
                            $reflectionParams[$i]->getType()->__toString() ==
                            gettype($params[$i]))
                    )
                ) {
                    $matched = false;
                    break;
                }

            }

            if($matched){
                call_user_func_array(array($this,$constructor->getName()),
                    $params);
                $finish = true;
                break;
            }
        }

        unset($constructor);

        if(!$finish){
            throw new \InvalidArgumentException("Cannot match construct by params");
        }
    }

}

使用它:

class MultiConstructorClass{

    use GenericConstructorOverloadTrait;

    private $param1;

    private $param2;

    private $param3;

    public function __construct1($param1, array $param2)
    {
        $this->param1 = $param1;
        $this->param2 = $param2;
    }

    public function __construct2($param1, array $param2, \DateTime $param3)
    {
        $this->__construct1($param1, $param2);
        $this->param3 = $param3;
    }

    /**
     * @return \DateTime
     */
    public function getParam3()
    {
        return $this->param3;
    }

    /**
     * @return array
     */
    public function getParam2()
    {
        return $this->param2;
    }

    /**
     * @return mixed
     */
    public function getParam1()
    {
        return $this->param1;
    }
}

其他回答

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

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));
    }
}

正如这里已经展示的,在PHP中有许多方法来声明多个构造函数,但是没有一种方法是正确的(因为PHP技术上不允许这样做)。 但这并不能阻止我们破解这个功能…… 下面是另一个例子:

<?php

class myClass {
    public function __construct() {
        $get_arguments       = func_get_args();
        $number_of_arguments = func_num_args();

        if (method_exists($this, $method_name = '__construct'.$number_of_arguments)) {
            call_user_func_array(array($this, $method_name), $get_arguments);
        }
    }

    public function __construct1($argument1) {
        echo 'constructor with 1 parameter ' . $argument1 . "\n";
    }

    public function __construct2($argument1, $argument2) {
        echo 'constructor with 2 parameter ' . $argument1 . ' ' . $argument2 . "\n";
    }

    public function __construct3($argument1, $argument2, $argument3) {
        echo 'constructor with 3 parameter ' . $argument1 . ' ' . $argument2 . ' ' . $argument3 . "\n";
    }
}

$object1 = new myClass('BUET');
$object2 = new myClass('BUET', 'is');
$object3 = new myClass('BUET', 'is', 'Best.');

使用和理解多个构造函数的最简单方法:

希望这能有所帮助。:)

在创建具有不同签名的多个构造函数时,我也面临着同样的问题,但不幸的是,PHP没有提供直接的方法来这样做。然而,我发现了一个技巧来克服它。希望也适用于你们所有人。

    <?PHP

    class Animal
    {

      public function __construct()
      {
        $arguments = func_get_args();
        $numberOfArguments = func_num_args();

        if (method_exists($this, $function = '__construct'.$numberOfArguments)) {
            call_user_func_array(array($this, $function), $arguments);
        }
    }
   
    public function __construct1($a1)
    {
        echo('__construct with 1 param called: '.$a1.PHP_EOL);
    }
   
    public function __construct2($a1, $a2)
    {
        echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
    }
   
    public function __construct3($a1, $a2, $a3)
    {
        echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
    }
}

$o = new Animal('sheep');
$o = new Animal('sheep','cat');
$o = new Animal('sheep','cat','dog');

// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog

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 A 
{ 
    function __construct($argument)
    { 
       $type = gettype($argument);

       if($type == 'unknown type')
       {
            // type unknown
       }

       $this->{'__construct_'.$type}($argument);
    } 

    function __construct_boolean($argument) 
    { 
        // do something
    }
    function __construct_integer($argument) 
    { 
        // do something
    }
    function __construct_double($argument) 
    { 
        // do something
    }
    function __construct_string($argument) 
    { 
        // do something
    }
    function __construct_array($argument) 
    { 
        // do something
    }
    function __construct_object($argument) 
    { 
        // do something
    }
    function __construct_resource($argument) 
    { 
        // do something
    }

    // other functions

}