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


当前回答

这是我对它的看法(为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

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

其他回答

我可能会这样做:

<?php

class Student
{
    public function __construct() {
        // allocate your stuff
    }

    public static function withID( $id ) {
        $instance = new self();
        $instance->loadByID( $id );
        return $instance;
    }

    public static function withRow( array $row ) {
        $instance = new self();
        $instance->fill( $row );
        return $instance;
    }

    protected function loadByID( $id ) {
        // do query
        $row = my_awesome_db_access_stuff( $id );
        $this->fill( $row );
    }

    protected function fill( array $row ) {
        // fill all properties from array
    }
}

?>

然后,如果我想要一个学生,我知道ID:

$student = Student::withID( $id );

或者如果我有一个db行数组:

$student = Student::withRow( $row );

从技术上讲,您不需要构建多个构造函数,而只是静态帮助方法,但是这样可以避免构造函数中的大量意大利面条代码。

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

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

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!

嗯,很惊讶我还没有看到这个答案,假设我要参加竞选。

class Action {
    const cancelable    =   0;
    const target        =   1
    const type          =   2;

    public $cancelable;
    public $target;
    public $type;


    __construct( $opt = [] ){

        $this->cancelable   = isset($opt[cancelable]) ? $opt[cancelable] : true;
        $this->target       = isset($opt[target]) ?     $opt[target] : NULL;
        $this->type         = isset($opt[type]) ?       $opt[type] : 'action';

    }
}


$myAction = new Action( [
    Action::cancelable => false,
    Action::type => 'spin',
    .
    .
    .
]);

您可以选择将这些选项分离到它们自己的类中,例如扩展脾。

abstract class ActionOpt extends SplEnum{
    const cancelable    =   0;
    const target        =   1
    const type          =   2;
}

你可以这样做:

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

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

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

编辑,

我可以加上

func_num_args()

会给出函数的参数个数。