PHP birden kurucular yapmanın en iyi yolu

10 Cevap php

İki __ PHP sınıfında benzersiz argüman imzaları ile fonksiyonları inşa koyamazsınız. Ben bunu yapmak istiyorum:

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 bunu yapmanın en iyi yolu nedir?

10 Cevap

Herhalde böyle bir şey yapmak istiyorum:

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

?>

Sonra i kimliğini biliyorum Öğrenci istiyorum:

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

Ya da ben db satır bir dizi varsa:

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

Teknik Birden Kurucular, sadece statik yardımcı yöntemler bina değil, ancak yapıcı spagetti kod bir sürü bu şekilde önlemek için olsun.

PHP dinamik bir dildir, bu yüzden yöntemleri aşırı olamaz. Bu gibi argüman türlerini kontrol etmek gerekir:

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

Kris çözümü gerçekten güzel, ama ben fabrika ve daha akıcı tarzı karışımı bulmak:

<?php

class Student
{
    /**
     * 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 withFirstName( $firstName) {
        $this->setFirstName( $firstname);
        return $this;
    }

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

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

}

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

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

Şimdi $ paramters değerlerin 'One', 'İki', 3 ile bir dizi olacak.

Düzenlemek,

Bunu ekleyebilir

func_num_args()

işlevine size parametrelerin sayısını verecektir.

Böyle bir şey yapabilirsiniz:

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

Sürüm 5.4 itibariyle, PHP destekler traits. Bu not tam olarak ne arıyorsun, ama basit bir özellik tabanlı bir yaklaşım olacaktır:

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

Biz iki sınıfa, biraz karşı-üretken her yapıcısı için biri ile sona. Bazı aklı korumak için, ben bir fabrikada atarım:

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

Yani, bütün bu aşağı gelir:

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

Bu korkunç ayrıntılı bir yaklaşım, ama son derece kullanışlı olabilir.

Diğer açıklamalarda belirtildiği gibi php yüklenme desteklemiyor gibi, genellikle yapıcısındaki "hileler kontrol tipi" kaçınılması ve fabrika desen intead kullanılır

yani.

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

Bildiğim kadarıyla aşırı yüklenmelerin PHP desteklenmiyor. Şunları yapabilirsiniz aşırı sadece aşırı properties 'get ve set yöntemleri (); (http://www.php.net/manual/en/overload.examples.basic.php)

Başka bir seçenek bu gibi yapıcı varsayılan argümanlar kullanmak için

class Student {

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

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

Bu, böyle bir satır ile örneğini gerekir demektir: $student = new Student($row['id'], $row) ama yapıcı güzel ve temiz tutar.

Eğer polimorfizmi yararlanmak istiyorsanız Öte yandan, o zaman bunu gibi iki sınıfları oluşturabilirsiniz:

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

Sen gerçekten kolay ve çok temiz aşağıdaki gibi bir şey yapabilirsiniz:

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