在 PHP 中执行多个构造函数的最佳方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1699796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 03:33:39  来源:igfitidea点击:

Best way to do multiple constructors in PHP

phpconstructormultiple-constructors

提问by Jannie Theunissen

You can't put two __construct functions with unique argument signatures in a PHP class. I'd like to do this:

您不能在 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.
   }
}

What is the best way to do this in PHP?

在 PHP 中执行此操作的最佳方法是什么?

回答by Kris

I'd probably do something like this:

我可能会做这样的事情:

<?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
    }
}

?>

Then if i want a Student where i know the ID:

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

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

Or if i have an array of the db row:

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

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

Technically you're not building multiple constructors, just static helper methods, but you get to avoid a lot of spaghetti code in the constructor this way.

从技术上讲,您不是在构建多个构造函数,只是在构建静态辅助方法,但是您可以通过这种方式避免在构造函数中使用大量意大利面条式代码。

回答by timaschew

Solution of Kris is really nice, but I find the mix of factory and fluent style better:

Kris 的解决方案真的很好,但我发现工厂和 fluent 风格的组合更好:

<?php

class Student
{

    protected $firstName;
    protected $lastName;
    // etc.

    /**
     * Constructor
     */
    public function __construct() {
        // allocate your stuff
    }

    /**
     * Static constructor / factory
     */
    public static function create() {
        $instance = new self();
        return $instance;
    }

    /**
     * FirstName setter - fluent style
     */
    public function setFirstName( $firstName) {
        $this->firstName = $firstName;
        return $this;
    }

    /**
     * LastName setter - fluent style
     */
    public function setLastName( $lastName) {
        $this->lastName = $lastName;
        return $this;
    }

}

// create instance
$student= Student::create()->setFirstName("John")->setLastName("Doe");

// see result
var_dump($student);
?>

回答by Daff

PHP is a dynamic language, so you can't overload methods. You have to check the types of your argument like this:

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.  
    }
}

回答by Bj?rn

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

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

Now $paramters will be an array with the values 'One', 'Two', 3.

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

Edit,

编辑,

I can add that

我可以补充一点

func_num_args()

will give you the number of parameters to the function.

将为您提供该函数的参数数量。

回答by Nasif Md. Tanjim

As has already been shown here, there are many ways of declaring multipleconstructors in PHP, but none of them are the correctway of doing so (since PHP technically doesn't allow it). But it doesn't stop us from hacking this functionality... Here's another example:

正如这里已经展示的那样,multiple在 PHP 中有很多声明构造函数的方法,但没有correct一种方法是这样做的(因为 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.');

Source:The easiest way to use and understand multiple constructors:

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

Hope this helps. :)

希望这可以帮助。:)

回答by yannis

As of version 5.4, PHP supports traits. This is notexactly what you are looking for, but a simplistic trait based approach would be:

从 5.4 版本开始,PHP 支持traits。这并不完全是您要寻找的,但基于简单特征的方法是:

trait StudentTrait {
    protected $id;
    protected $name;

    final public function setId($id) {
        $this->id = $id;
        return $this;
    }

    final public function getId() { return $this->id; }

    final public function setName($name) {
        $this->name = $name; 
        return $this;
    }

    final public function getName() { return $this->name; }

}

class Student1 {
    use StudentTrait;

    final public function __construct($id) { $this->setId($id); }
}

class Student2 {
    use StudentTrait;

    final public function __construct($id, $name) { $this->setId($id)->setName($name); }
}

We end up with two classes, one for each constructor, which is a bit counter-productive. To maintain some sanity, I'll throw in a factory:

我们最终得到两个类,一个用于每个构造函数,这有点适得其反。为了保持理智,我将投入一个工厂:

class StudentFactory {
    static public function getStudent($id, $name = null) {
        return 
            is_null($name)
                ? new Student1($id)
                : new Student2($id, $name)
    }
}

So, it all comes down to this:

所以,这一切都归结为:

$student1 = StudentFactory::getStudent(1);
$student2 = StudentFactory::getStudent(1, "yannis");

It's a horribly verbose approach, but it can be extremely convenient.

这是一种非常冗长的方法,但它可以非常方便。

回答by Andrei Serdeliuc ?

You could do something like this:

你可以这样做:

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

回答by rojoca

Another option is to use default arguments in the constructor like this

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

class Student {

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

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

This means you'll need to instantiate with a row like this: $student = new Student($row['id'], $row)but keeps your constructor nice and clean.

这意味着您需要使用这样的行实例化:$student = new Student($row['id'], $row)但要保持您的构造函数干净整洁。

On the other hand, if you want to make use of polymorphism then you can create two classes like so:

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

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

回答by gpilotino

as stated in the other comments, as php does not support overloading, usually the "type checking tricks" in constructor are avoided and the factory pattern is used intead

如其他评论中所述,由于 php 不支持重载,通常会避免构造函数中的“类型检查技巧”,而是使用工厂模式

ie.

IE。

$myObj = MyClass::factory('fromInteger', $params);
$myObj = MyClass::factory('fromRow', $params);

回答by paishin

You could do something like the following which is really easy and very clean:

您可以执行以下操作,这非常简单且非常干净:

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

   switch(sizeof(func_get_args()))      
   {
    case 0: //No arguments
        break; 
    case 1: //One argument
        $this->do_something($arguments[0]); 
        break;              
    case 2:  //Two arguments
        $this->do_something_else($arguments[0], $arguments[1]); 
        break;            
   }
}