сайтов - конструктор php 7




Лучший способ сделать несколько конструкторов в PHP (13)

Вы не можете поместить две функции __construct с уникальными сигнатурами сигнатур в классе PHP. Я бы хотел сделать это:

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 - динамический язык, поэтому вы не можете перегружать методы. Вы должны проверить типы своих аргументов следующим образом:

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

В ответ на лучший ответ Криса (который удивительно помог разработать мой собственный класс btw), здесь приведена модифицированная версия для тех, которые могут оказаться полезными. Включает методы для выбора из любого столбца и данных объекта демпинга из массива. Ура!

public function __construct() {
    $this -> id = 0;
    //...
}

public static function Exists($id) {
    if (!$id) return false;
    $id = (int)$id;
    if ($id <= 0) return false;
    $mysqli = Mysql::Connect();
    if (mysqli_num_rows(mysqli_query($mysqli, "SELECT id FROM users WHERE id = " . $id)) == 1) return true;
    return false;
}

public static function FromId($id) {
    $u = new self();
    if (!$u -> FillFromColumn("id", $id)) return false;
    return $u;
}

public static function FromColumn($column, $value) {
    $u = new self();
    if (!$u -> FillFromColumn($column, $value)) return false;
    return $u;
}

public static function FromArray($row = array()) {
    if (!is_array($row) || $row == array()) return false;
    $u = new self();
    $u -> FillFromArray($row);
    return $u;
}

protected function FillFromColumn($column, $value) {
    $mysqli = Mysql::Connect();
    //Assuming we're only allowed to specified EXISTENT columns
    $result = mysqli_query($mysqli, "SELECT * FROM users WHERE " . $column . " = '" . $value . "'");
    $count = mysqli_num_rows($result);
    if ($count == 0) return false;
    $row = mysqli_fetch_assoc($result);
    $this -> FillFromArray($row);
}

protected function FillFromArray(array $row) {
    foreach($row as $i => $v) {
        if (isset($this -> $i)) {
            $this -> $i = $v;
        }
    }
}

public function ToArray() {
    $m = array();
    foreach ($this as $i => $v) {
        $m[$i] = $v;    
    }
    return $m;
}

public function Dump() {
    print_r("<PRE>");
    print_r($this -> ToArray());
    print_r("</PRE>");  
}

Вы могли бы сделать что-то вроде этого:

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

Вы можете сделать что-то вроде следующего, что действительно легко и очень чисто:

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

Другой вариант - использовать аргументы по умолчанию в конструкторе, подобном этому

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

Как уже было показано здесь, существует много способов объявления 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.');

Источник: самый простой способ использования и понимания нескольких конструкторов:

Надеюсь это поможет. :)


На этот вопрос уже были ответы очень разумные способы выполнить требование, но мне интересно, почему бы не сделать шаг назад и задать основной вопрос, почему нам нужен класс с двумя конструкторами? Если моему классу нужны два конструктора, то, вероятно, именно так, как я разрабатываю свои классы, требуется немного больше внимания, чтобы придумать более чистую и более проверяемую конструкцию.

Мы пытаемся смешивать процесс создания класса с фактической логикой класса.

Если объект Student находится в допустимом состоянии, имеет значение, если он был создан из строки базы данных или данных из веб-формы или запроса cli?

Теперь, чтобы ответить на вопрос, что это может возникнуть здесь, если мы не добавим логику создания объекта из строки db, то как мы создадим объект из данных db, мы можем просто добавить другой класс, назовем его StudentMapper if вам удобно работать с шаблоном карт данных, в некоторых случаях вы можете использовать StudentRepository, и если ничто не соответствует вашим потребностям, вы можете сделать StudentFactory для решения всех задач по строительству объектов.

Суть заключается в том, чтобы сохранить слой устойчивости на голове, когда мы работаем над объектами домена.


Насколько я знаю, перегрузка не поддерживается в PHP. Вы можете перегружать свойства get и set методами с помощью функции overload (); ( http://www.php.net/manual/en/overload.examples.basic.php )


Позвольте мне добавить здесь свое зерно песка

Мне лично нравится добавлять конструкторы в качестве статических функций, возвращающих экземпляр класса (объекта). Ниже приведен пример кода:

 class Person
 {
     private $name;
     private $email;

     public static function withName($name)
     {
         $person = new Person();
         $person->name = $name;

         return $person;
     }

     public static function withEmail($email)
     {
         $person = new Person();
         $person->email = $email;

         return $person;
     }
 }

Обратите внимание, что теперь вы можете создать экземпляр класса Person следующим образом:

$person1 = Person::withName('Example');
$person2 = Person::withEmail('[email protected]_email.com');

Я взял этот код из:

http://alfonsojimenez.com/post/30377422731/multiple-constructors-in-php


Решение Криса действительно приятно, но я считаю, что сочетание фабрики и свободного стиля лучше:

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

Я знаю, что я очень опаздываю на вечеринку здесь, но я придумал довольно гибкий шаблон, который должен позволить некоторые действительно интересные и универсальные реализации.

Настройте свой класс, как обычно, с любыми переменными, которые вам нравятся.

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

Когда вы делаете свой объект, просто передавайте ассоциативный массив с ключами массива так же, как имена ваших варов, например ...

$sample_variable = new MyClass([
    'myVar2'=>123, 
    'i_dont_want_this_one'=> 'This won\'t make it into the class'
    ]);

print_r($sample_variable);

print_r($sample_variable); после этого экземпляра получается следующее:

MyClass Object ( [myVar1:protected] => [myVar2:protected] => 123 )

Поскольку мы инициализировали $group нулевым значением в нашем __construct(...) , это также верно, чтобы ничего не передавать и в конструкторе, например ...

$sample_variable = new MyClass();

print_r($sample_variable);

Теперь результат точно такой, как ожидалось:

MyClass Object ( [myVar1:protected] => [myVar2:protected] => )

Причина, по которой я написал это, состояла в том, что я мог напрямую передать вывод json_decode(...) моему конструктору и не беспокоиться об этом слишком много.

Это было выполнено в PHP 7.1. Наслаждайтесь!


Я создал этот метод, чтобы использовать его не только для конструкторов, но и для методов:

Мой конструктор:

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

или же

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

и так далее :)

И при использовании:

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

он вызовет __constructN , где вы определили N args

затем $ myObject -> doSomething ($ arg1, $ arg2, ..., $ argM)

он будет вызывать doSomethingM где вы определили M args;


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

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

Теперь $ paramters будет массивом со значениями «Один», «Два», 3.

Редактировать,

Могу добавить, что

func_num_args()

даст вам количество параметров функции.







multiple-constructors