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


当前回答

你可以这样做:

public function __construct($param)
{
    if(is_int($param)) {
         $this->id = $param;
    } elseif(is_object($param)) {
     // do something else
    }
 }

其他回答

我创建这个方法是为了让它不仅在构造函数中使用,而且在方法中使用:

我的构造函数:

function __construct() {
    $paramsNumber=func_num_args();
    if($paramsNumber==0){
        //do something
    }else{
        $this->overload('__construct',func_get_args());
    }
}

我的doSomething方法:

public function doSomething() {
    $paramsNumber=func_num_args();
    if($paramsNumber==0){
        //do something
    }else{
        $this->overload('doSomething',func_get_args());
    }
}

两者都使用这个简单的方法:

public function overloadMethod($methodName,$params){
    $paramsNumber=sizeof($params);
    //methodName1(), methodName2()...
    $methodNameNumber =$methodName.$paramsNumber;
    if (method_exists($this,$methodNameNumber)) {
        call_user_func_array(array($this,$methodNameNumber),$params);
    }
}

所以你可以声明

__construct1($arg1), __construct2($arg1,$arg2)...

or

methodName1($arg1), methodName2($arg1,$arg2)...

等等。

使用时:

$myObject =  new MyClass($arg1, $arg2,..., $argN);

它将调用__constructN,在那里你定义了N个参数

然后 $myObject -> doSomething($arg1, $arg2,..), argM美元)

它会调用doSomethingM,在这里你定义了M个参数;

这个问题已经用非常聪明的方法回答了,但我想知道为什么不退一步,问一个基本的问题,为什么我们需要一个有两个构造函数的类? 如果我的类需要两个构造函数,那么我设计类的方式可能需要更多的考虑,以提出一个更干净、更可测试的设计。

我们正在尝试混合如何实例化一个类与实际的类逻辑。

如果一个学生对象是在一个有效的状态,那么它是否从一个DB或从一个web表单或cli请求的数据行构造?

现在回答这个问题,可能出现的,如果我们不添加从db行创建一个对象的逻辑,那么我们如何创建一个对象从数据库数据,我们可以简单地添加另一个类,称之为StudentMapper如果你熟悉数据映射模式,在某些情况下,您可以使用StudentRepository,如果没有适合你的需要你可以StudentFactory处理所有类型的对象建设任务。

当我们在处理领域对象时,底线是不要考虑持久化层。

我知道我在这方面非常晚,但我提出了一个相当灵活的模式,应该允许一些真正有趣和通用的实现。

像往常一样设置类,使用您喜欢的任何变量。

class MyClass{ protected $myVar1; protected $myVar2; public function __construct($obj = null){ if($obj){ foreach (((object)$obj) as $key => $value) { if(isset($value) && in_array($key, array_keys(get_object_vars($this)))){ $this->$key = $value; } } } } } When you make your object just pass an associative array with the keys of the array the same as the names of your vars, like so... $sample_variable = new MyClass([ 'myVar2'=>123, 'i_dont_want_this_one'=> 'This won\'t make it into the class' ]); print_r($sample_variable); The print_r($sample_variable); after this instantiation yields the following: MyClass Object ( [myVar1:protected] => [myVar2:protected] => 123 ) Because we've initialize $group to null in our __construct(...), it is also valid to pass nothing whatsoever into the constructor as well, like so... $sample_variable = new MyClass(); print_r($sample_variable); Now the output is exactly as expected: MyClass Object ( [myVar1:protected] => [myVar2:protected] => ) The reason I wrote this was so that I could directly pass the output of json_decode(...) to my constructor, and not worry about it too much. This was executed in PHP 7.1. Enjoy!

这是我对它的看法(为php 5.6构建)。

它将查看构造函数参数类型(数组,类名,无描述)并比较给定的参数。构造函数必须在最后以最少的特异性给出。例子:

// demo class
class X {
    public $X;

    public function __construct($x) {
        $this->X = $x;
    }

    public function __toString() {
        return 'X'.$this->X;
    }
}

// demo class
class Y {
    public $Y;

    public function __construct($y) {
        $this->Y = $y;
    }
    public function __toString() {
        return 'Y'.$this->Y;
    }
}

// here be magic
abstract class MultipleConstructors {
    function __construct() {
        $__get_arguments       = func_get_args();
        $__number_of_arguments = func_num_args();

        $__reflect = new ReflectionClass($this);
        foreach($__reflect->getMethods() as $__reflectmethod) {
            $__method_name = $__reflectmethod->getName();
            if (substr($__method_name, 0, strlen('__construct')) === '__construct') {
                $__parms = $__reflectmethod->getParameters();
                if (count($__parms) == $__number_of_arguments) {
                    $__argsFit = true;
                    foreach ($__parms as $__argPos => $__param) {
                        $__paramClass= $__param->getClass();
                        $__argVar = func_get_arg($__argPos);
                        $__argVarType = gettype($__argVar);
                        $__paramIsArray = $__param->isArray() == true;
                        $__argVarIsArray = $__argVarType == 'array';
                        // parameter is array and argument isn't, or the other way around.
                        if (($__paramIsArray && !$__argVarIsArray) ||
                            (!$__paramIsArray && $__argVarIsArray)) {
                            $__argsFit = false;
                            continue;
                        }
                        // class check
                        if ((!is_null($__paramClass) && $__argVarType != 'object') ||
                            (is_null($__paramClass) && $__argVarType == 'object')){
                            $__argsFit = false;
                            continue;
                        }
                        if (!is_null($__paramClass) && $__argVarType == 'object') {
                            // class type check
                            $__paramClassName = "N/A";
                            if ($__paramClass)
                                $__paramClassName = $__paramClass->getName();
                            if ($__paramClassName != get_class($__argVar)) {
                                $__argsFit = false;
                            }
                        }
                    }
                    if ($__argsFit) {
                        call_user_func_array(array($this, $__method_name), $__get_arguments);
                        return;
                    }
                }
            }
        }
        throw new Exception("No matching constructors");
    }
}

// how to use multiple constructors
class A extends MultipleConstructors {
    public $value;

    function __constructB(array $hey) {
        $this->value = 'Array#'.count($hey).'<br/>';
    }
    function __construct1(X $first) {
        $this->value = $first .'<br/>';
    }

    function __construct2(Y $second) {
        $this->value = $second .'<br/>';
    }
    function __constructA($hey) {
        $this->value = $hey.'<br/>';
    }

    function __toString() {
        return $this->value;
    }
}

$x = new X("foo");
$y = new Y("bar");

$aa = new A(array("one", "two", "three"));
echo $aa;

$ar = new A("baz");
echo $ar;

$ax = new A($x);
echo $ax;

$ay = new A($y);
echo $ay;

结果:

Array#3
baz
Xfoo
Ybar

如果没有找到构造函数,可以将其删除并允许构造函数为“空”,而不是终止异常。或者你喜欢什么都行。

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

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