Question Meilleur moyen de faire plusieurs constructeurs en PHP


Vous ne pouvez pas mettre deux fonctions __construct avec des signatures d'argument uniques dans une classe PHP. Je voudrais faire ceci:

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

Quelle est la meilleure façon de le faire en PHP?


291
2017-11-09 08:43


origine


Réponses:


Je ferais probablement quelque chose comme ça:

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

?>

Alors si je veux un étudiant où je connais l'identifiant:

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

Ou si j'ai un tableau de la ligne de base de données:

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

Techniquement, vous ne construisez pas plusieurs constructeurs, seulement des méthodes statiques, mais vous évitez ainsi beaucoup de code spaghetti dans le constructeur.


399
2017-11-09 14:33



La solution de Kris est vraiment sympa, mais je trouve que le mélange de style d'usine et de style courant est meilleur:

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

75
2017-09-21 07:39



PHP est un langage dynamique, donc vous ne pouvez pas surcharger les méthodes. Vous devez vérifier les types de votre argument comme ceci:

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

39
2017-11-09 08:48



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

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

Maintenant, $ paramters sera un tableau avec les valeurs "One", "Two", 3.

Modifier,

Je peux ajouter que

func_num_args()

vous donnera le nombre de paramètres à la fonction.


20
2017-11-09 08:47



Depuis la version 5.4, PHP prend en charge traits. C'est ne pas exactement ce que vous cherchez, mais une approche basée sur les traits simplistes serait:

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

Nous nous retrouvons avec deux classes, une pour chaque constructeur, ce qui est un peu contre-productif. Pour maintenir une certaine santé mentale, je vais jeter dans une usine:

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

Donc, tout se résume à ceci:

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

C'est une approche horriblement verbeuse, mais cela peut être extrêmement pratique.


13
2018-03-01 08:45



Comme cela a déjà été montré ici, il existe plusieurs façons de déclarer multiple constructeurs en PHP, mais aucun n'est le correct façon de le faire (puisque PHP ne le permet pas techniquement). Mais cela ne nous empêche pas de pirater cette fonctionnalité ... Voici un autre exemple:

<?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.');

La source:  Le moyen le plus simple d'utiliser et de comprendre plusieurs constructeurs:

J'espère que cela t'aides. :)


13
2018-01-24 06:52



Vous pourriez faire quelque chose comme ceci:

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

12
2017-11-09 08:47