Beste Möglichkeit, mehrere Konstruktoren in PHP zu erstellen

Lesezeit: 9 Minuten

Sie können nicht zwei __construct-Funktionen mit eindeutigen Argumentsignaturen in eine PHP-Klasse einfügen. Ich möchte dies tun:

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

Was ist der beste Weg, dies in PHP zu tun?

  • Ich träume auch von benannten Konstruktoren und Methodenüberladung +1

    – Funke

    4. November 2011 um 17:05 Uhr

  • In meinem Fall möchte ich einen geschützten Konstruktor haben, der ein weniger erforderliches Argument als der öffentliche hat – um seine Factory-Methode zu standardisieren. Ich brauche eine Klasse, um Kopien von sich selbst erstellen zu können, und die Fabrik befindet sich in einer abstrakten Klasse, aber die konkreten Klassen haben möglicherweise Konstruktoren, die ein zweites Argument erfordern – von dem die abstrakte Klasse keine Ahnung hat.

    – XedinUnbekannt

    16. September 2016 um 12:00 Uhr

  • Nicht wirklich etwas Wertvolles, aber etwas, worüber ich vor einiger Zeit gestolpert bin: Die Klasse DatePeriod in date_c.php hat mehrere Konstruktoren. Ich weiß aber nicht, was PHP intern damit macht.

    – ein Progger

    7. August 2020 um 8:29 Uhr


Ich würde wahrscheinlich so etwas tun:

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

?>

Dann, wenn ich einen Studenten will, wo ich die ID kenne:

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

Oder wenn ich ein Array der DB-Zeile habe:

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

Technisch gesehen bauen Sie nicht mehrere Konstruktoren, sondern nur statische Hilfsmethoden, aber auf diese Weise vermeiden Sie viel Spaghetti-Code im Konstruktor.

  • Sieht so aus, als hätten Sie gerade die Frage beantwortet, die ich gpilotino gestellt habe. Danke! Sehr deutlich.

    – Jannie Theunissen

    9. November 2009 um 14:48 Uhr

  • @gpilotino, Overkill, weil Sie noch eine weitere Klasse (oder Methode) benötigen würden, die im Grunde nur aus einem Switch/Case-Entscheidungsbaum bestehen würde, und am Ende nur das tun würde, was ich bereits in zwei Methoden getan habe. Factories sind in Situationen nützlicher, in denen Sie die genauen Einschränkungen eines Problems nicht einfach definieren können, z. B. beim Erstellen von Formularelementen. aber das ist nur meine Meinung und fürs Protokoll; Ich behaupte nicht, dass es Tatsache ist.

    – Kris

    9. November 2009 um 16:24 Uhr

  • Und das konnten wir auch nicht machen __construct() private, um zu verhindern, dass jemand gelegentlich eine “nicht initialisierte” Instanz zuweist?

    – mlvljr

    13. April 2011 um 15:08 Uhr

  • @mlvljr: Sie könnten, aber ich würde vorschlagen, es geschützt statt privat zu machen. Andernfalls werden Sie höchstwahrscheinlich in Schwierigkeiten geraten, wenn Sie Ihre Klasse jemals verlängern.

    – Kris

    23. April 2011 um 23:20 Uhr

  • Hinweis ab PHP 5.3 sollten Sie wahrscheinlich verwenden new static() eher, als new self()seit new static() wird in Kinderklassen vernünftiger arbeiten.

    – Buttle Butkus

    26. Mai 2014 um 1:59 Uhr

Beste Moglichkeit mehrere Konstruktoren in PHP zu erstellen
timaschew

Die Lösung von Kris ist wirklich nett, aber ich bevorzuge eine Mischung aus Fabrik und fließendem Stil:

<?php

class Student
{

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

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

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

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

  • +1; Diese Art von Lösung kann wirklich schönen Code ergeben. Obwohl ich mich dafür entscheiden würde setLastName (oder besser gesagt alle Setter) in diese Lösung zurückkehren $this anstatt effektiv zwei Setter auf demselben Grundstück zu haben.

    – Kris

    26. August 2013 um 22:23 Uhr

  • Als jemand, der an kompilierte, statisch typisierte Sprachen wie C# gewöhnt ist, passt diese Vorgehensweise einfach gut zu mir.

    – Adam

    11. Juli 2014 um 11:35 Uhr

  • Wie unterscheidet sich die Bereitstellung einer statischen Erstellungsmethode von der einfachen Verwendung des Konstruktors auf die gleiche Weise? $student = new Student()->setFirstName("John")->setLastName("Doe");

    – Jeger

    30. Mai 2016 um 15:11 Uhr


  • Bei diesem Code gibt es ein wichtiges Problem: Sie können nicht sicherstellen, dass die Instanz gültig ist (deshalb gibt es Konstruktoren), und normalerweise sind unveränderliche Klassen vorzuziehen.

    – Pedro Amaral Couto

    16. April 2017 um 11:53 Uhr

  • Dies ist der sauberste Code, der für solche Fragen gesehen wird, und er kann durch Verwendung sauberer sein return new self() in dem create() Methode

    – Nasari

    25. Januar 2021 um 14:45 Uhr

1646348049 204 Beste Moglichkeit mehrere Konstruktoren in PHP zu erstellen
Daff

PHP ist eine dynamische Sprache, daher können Sie Methoden nicht überladen. Sie müssen die Typen Ihres Arguments wie folgt überprüfen:

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

  • Alles, was dazu führt, ist fantastischer Spaghetti-Code. Aber es ist in der Tat wahrscheinlich der einfachste Weg, dies zu tun.

    – Kris

    9. November 2009 um 14:35 Uhr

  • Wenn Sie Ihre Konstruktoren wie in einer statisch typisierten Sprache erstellen, wird daraus Spaghetti-Code. Aber du nicht. Das Erstellen von zwei Konstruktoren mit einem Parameter und keinem Typ (no type == any type) für diesen Parameter funktioniert ohnehin in keiner Sprache (z. B. funktioniert es auch nicht, zwei Java-Konstruktoren mit jeweils einem Object-Parameter in einer Klasse zu haben ).

    – Daff

    9. November 2009 um 15:08 Uhr

  • Was ich meinte, ist, dass Sie verschiedene Dinge im selben Umfang tun, basierend auf äußeren Einflüssen. Es ist keine schlechte Lösung (da es funktionieren wird), nur nicht die, die ich wählen würde.

    – Kris

    9. November 2009 um 16:27 Uhr

  • Eine Sprache, die “dynamisch” ist, schließt die Möglichkeit von Funktions-/Konstruktorüberladungen nicht aus. Es schließt nicht einmal die statische Typisierung aus. Und selbst wenn, gäbe es immer noch die Möglichkeit, Überladungen nur auf der Grundlage der Argumentanzahl zuzulassen. Bitte verwenden Sie “dynamisch” nicht als Ausrede für Dinge.

    – Sebastian Mach

    13. Januar 2015 um 10:08 Uhr


  • Ich mag dies, um den Code für den Benutzer der Klasse zu vereinfachen, und es erfüllt das, was das OP wollte. Es wird kein Spaghetti-Code sein, wenn Sie zwei Funktionen erstellen (wie die Antwort von Kris) und die Funktionen einfach im Konstruktor entsprechend aufrufen. Der Code zum Überprüfen von Argumenten ist wahrscheinlich nicht so kompliziert. Dies setzt natürlich voraus, dass es eine Möglichkeit gibt, die Argumente wie in diesem Fall voneinander zu unterscheiden.

    – Dovev Hefetz

    3. November 2015 um 13:56 Uhr


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

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

Jetzt ist $parameters ein Array mit den Werten ‘Eins’, ‘Zwei’, 3.

Bearbeiten,

Das kann ich hinzufügen

func_num_args()

gibt Ihnen die Anzahl der Parameter für die Funktion.

Beste Moglichkeit mehrere Konstruktoren in PHP zu erstellen
Nasif Md. Tanjim

Wie hier bereits gezeigt wurde, gibt es viele Möglichkeiten der Deklaration multiple Konstruktoren in PHP, aber keiner von ihnen ist der correct Art und Weise, dies zu tun (da PHP dies technisch nicht zulässt). Aber es hält uns nicht davon ab, diese Funktionalität zu hacken … Hier ist ein weiteres Beispiel:

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

Quelle: Der einfachste Weg, mehrere Konstruktoren zu verwenden und zu verstehen:

Hoffe das hilft. 🙂

  • Dies ist die beste Lösung. Kann noch eleganter sein, wenn Sie PHP 5.6+ mit dem neuen verwenden ... Operator.

    – Chris Bornhoft

    1. April 2015 um 18:28 Uhr

  • Natürlich funktioniert dies nicht mit JannieTs ursprünglicher Frage, da ihre gewünschten Konstruktoren waren __construct($id) und __construct($row_from_database). Beide haben ein Argument, vermutlich entweder ein int für die erste und eine Reihe oder Objekt zum zweiten. Das Anhängen einer Zahl könnte natürlich zu einer Art Argumentsignatur im C++-Stil erweitert werden (d. h. __construct_i($intArg) und __construct_a($arrayArg)).

    – LavaSlider

    2. September 2015 um 13:21 Uhr

  • +1: Ich mag das irgendwie, aber erweitert mit Typinformationen und ohne die doppelten Unterstrich-Präfixe in den verschachtelten ctors. Danke für die Inspiration!

    – Kris

    23. November 2015 um 23:04 Uhr

  • Sie könnten Ihrem Beispielcode sogar Reflektion hinzufügen, um Typprüfungen auf Parameter jeder Funktion der Klasse anzuwenden, die mit __construct beginnt, und auf diese Weise den entsprechenden Konstruktor abgleichen

    – Tom Kraak

    26. Februar 2020 um 12:28 Uhr

Beste Moglichkeit mehrere Konstruktoren in PHP zu erstellen
Andrei Serdeliuc ॐ

Du könntest so etwas machen:

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

  • Dies ist die beste Lösung. Kann noch eleganter sein, wenn Sie PHP 5.6+ mit dem neuen verwenden ... Operator.

    – Chris Bornhoft

    1. April 2015 um 18:28 Uhr

  • Natürlich funktioniert dies nicht mit JannieTs ursprünglicher Frage, da ihre gewünschten Konstruktoren waren __construct($id) und __construct($row_from_database). Beide haben ein Argument, vermutlich entweder ein int für die erste und eine Reihe oder Objekt zum zweiten. Das Anhängen einer Zahl könnte natürlich zu einer Art Argumentsignatur im C++-Stil erweitert werden (d. h. __construct_i($intArg) und __construct_a($arrayArg)).

    – LavaSlider

    2. September 2015 um 13:21 Uhr

  • +1: Ich mag das irgendwie, aber erweitert mit Typinformationen und ohne die doppelten Unterstrich-Präfixe in den verschachtelten ctors. Danke für die Inspiration!

    – Kris

    23. November 2015 um 23:04 Uhr

  • Sie könnten Ihrem Beispielcode sogar Reflektion hinzufügen, um Typprüfungen auf Parameter jeder Funktion der Klasse anzuwenden, die mit __construct beginnt, und auf diese Weise den entsprechenden Konstruktor abgleichen

    – Tom Kraak

    26. Februar 2020 um 12:28 Uhr

1646348050 335 Beste Moglichkeit mehrere Konstruktoren in PHP zu erstellen
Yannis

Ab Version 5.4 unterstützt PHP Züge. Das ist nicht genau das, wonach Sie suchen, aber ein vereinfachter, auf Merkmalen basierender Ansatz wäre:

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

Am Ende haben wir zwei Klassen, eine für jeden Konstruktor, was etwas kontraproduktiv ist. Um bei Verstand zu bleiben, werfe ich eine Fabrik ein:

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

Es läuft also alles darauf hinaus:

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

Es ist ein schrecklich ausführlicher Ansatz, aber es kann äußerst bequem sein.

928290cookie-checkBeste Möglichkeit, mehrere Konstruktoren in PHP zu erstellen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy