sourcecode

PHP에서 여러 생성자를 수행하는 가장 좋은 방법

copyscript 2022. 9. 11. 17:29
반응형

PHP에서 여러 생성자를 수행하는 가장 좋은 방법

하나의 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.
   }
}

이것을 PHP로 하는 가장 좋은 방법은 무엇입니까?

아마 이렇게 할 거예요.

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

?>

아이디를 알고 있는 학생이 필요한 경우:

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

또는 db 행 배열이 있는 경우:

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

엄밀히 말하면 여러 개의 컨스트럭터를 구축하는 것이 아니라 정적 도우미 메서드를 구축하는 것입니다만, 이러한 방법으로 컨스트럭터의 많은 스파게티 코드를 회피할 수 있습니다.

Kris의 솔루션은 매우 좋지만, 저는 팩토리와 유창한 스타일을 혼합한 것을 선호합니다.

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

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.  
    }
}
public function __construct() {
    $parameters = func_get_args();
    ...
}

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

이제 $paramters는 값 'One', 'Two', 3을 가진 배열이 됩니다.

편집,

덧붙일 수 있다

func_num_args()

함수에 대한 파라미터의 수가 표시됩니다.

있는 처럼, 「이러다」라고 선언하는 .multiple.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.');

출처: 여러 컨스트럭터를 사용하고 이해하는 가장 쉬운 방법은 다음과 같습니다.

이게 도움이 됐으면 좋겠다.:)

다음과 같은 작업을 수행할 수 있습니다.

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

버전 5.4에서 PHP는 특성을 지원합니다.이는 고객이 원하는 것은 아니지만 다음과 같은 단순한 특성 기반 접근법이 될 수 있습니다.

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

각 컨스트럭터별로 1개씩 2개의 클래스가 제공되기 때문에 다소 역효과가 있습니다.제정신을 유지하기 위해 공장을 설립합니다.

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

결론은 다음과 같습니다.

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

그것은 끔찍할 정도로 장황한 접근법이지만 매우 편리할 수 있다.

여기 그것을 하는 우아한 방법이 있다.매개 변수 수가 지정된 여러 생성자를 사용할 수 있는 특성을 만듭니다.함수 이름 '_constructure'에 파라미터 수를 추가하면 됩니다.따라서 하나의 파라미터는 "_construct1", 2개의 "_construct2" 등이 됩니다.

trait constructable
{
    public function __construct() 
    { 
        $a = func_get_args(); 
        $i = func_num_args(); 
        if (method_exists($this,$f='__construct'.$i)) { 
            call_user_func_array([$this,$f],$a); 
        } 
    } 
}

class a{
    use constructable;

    public $result;

    public function __construct1($a){
        $this->result = $a;
    }

    public function __construct2($a, $b){
        $this->result =  $a + $b;
    }
}

echo (new a(1))->result;    // 1
echo (new a(1,2))->result;  // 3

다른 옵션은 다음과 같이 생성자에서 기본 인수를 사용하는 것입니다.

class Student {

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

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

이런: 즉, 음, 음, 다, 다, 다, 즉, 즉, 다, 다, like, like, like, like, like, like, like, like, like, like, like, like, like.$student = new Student($row['id'], $row)컨스트럭터를 깔끔하게 유지할 수 있습니다.

한편, 다형성을 이용하고 싶은 경우는, 다음과 같은 2개의 클래스를 작성할 수 있습니다.

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

다른 코멘트에 기재되어 있듯이 php는 오버로드를 지원하지 않기 때문에 보통 컨스트럭터의 "타입 체크 트릭"은 피하고 공장 패턴은 내부에서 사용됩니다.

즉,

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

다음과 같은 매우 쉽고 깨끗한 작업을 수행할 수 있습니다.

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

이 질문은 이미 요건을 충족하기 위한 매우 현명한 방법으로 답변되었습니다만, 왜 우리는 두 개의 컨스트럭터를 가진 클래스가 필요한지 한 걸음 물러서서 기본적인 질문을 해보는 것이 어떨까요?만약 우리 반에 두 명의 컨스트럭터가 필요하다면, 아마도 내가 수업을 설계하는 방식은 더 깨끗하고 테스트 가능한 디자인을 만들기 위해 더 많은 고려가 필요하지 않을 것이다.

우리는 클래스를 인스턴스화하는 방법과 실제 클래스 논리를 혼합하려고 합니다.

Student 객체가 유효한 상태일 경우 DB의 행 또는 웹 폼의 데이터 또는 CLI 요청에서 생성된 데이터 중 어느 것이 중요한가요?

여기서 발생하는 질문에 답하기 위해 db 행에서 오브젝트를 작성하는 로직을 추가하지 않는 경우 DB 데이터에서 오브젝트를 작성하는 방법은 다른 클래스를 추가하기만 하면 됩니다.데이터 매퍼 패턴에 익숙하다면 Student Mapper라고 부릅니다.경우에 따라서는 Student Repository를 사용할 수 있습니다.Student Factory가 모든 종류의 객체 구축 태스크를 처리하도록 할 수 있습니다.

요점은 도메인 오브젝트에 대해 작업할 때 지속 레이어를 머릿속에 남기지 않도록 하는 것입니다.

파티에 늦었다는 건 알지만, 정말 흥미롭고 다재다능한 구현을 가능하게 하는 꽤 유연한 패턴을 생각해 냈습니다.

원하는 변수를 사용하여 평소처럼 클래스를 설정합니다.

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에서 실행되었습니다.맛있게 드세요!

이것이 저의 견해입니다(build for php 5.6).

생성자 매개 변수 유형(배열, 클래스 이름, 설명 없음)을 살펴보고 지정된 인수를 비교합니다.생성자는 마지막으로 가장 구체성이 낮은 상태로 제공되어야 합니다.예를 들면:

// demo class
class X {
    public $X;

    public function __construct($x) {
        $this->X = $x;
    }

    public function __toString() {
        return 'X'.$this->X;
    }
}

// demo class
class Y {
    public $Y;

    public function __construct($y) {
        $this->Y = $y;
    }
    public function __toString() {
        return 'Y'.$this->Y;
    }
}

// here be magic
abstract class MultipleConstructors {
    function __construct() {
        $__get_arguments       = func_get_args();
        $__number_of_arguments = func_num_args();

        $__reflect = new ReflectionClass($this);
        foreach($__reflect->getMethods() as $__reflectmethod) {
            $__method_name = $__reflectmethod->getName();
            if (substr($__method_name, 0, strlen('__construct')) === '__construct') {
                $__parms = $__reflectmethod->getParameters();
                if (count($__parms) == $__number_of_arguments) {
                    $__argsFit = true;
                    foreach ($__parms as $__argPos => $__param) {
                        $__paramClass= $__param->getClass();
                        $__argVar = func_get_arg($__argPos);
                        $__argVarType = gettype($__argVar);
                        $__paramIsArray = $__param->isArray() == true;
                        $__argVarIsArray = $__argVarType == 'array';
                        // parameter is array and argument isn't, or the other way around.
                        if (($__paramIsArray && !$__argVarIsArray) ||
                            (!$__paramIsArray && $__argVarIsArray)) {
                            $__argsFit = false;
                            continue;
                        }
                        // class check
                        if ((!is_null($__paramClass) && $__argVarType != 'object') ||
                            (is_null($__paramClass) && $__argVarType == 'object')){
                            $__argsFit = false;
                            continue;
                        }
                        if (!is_null($__paramClass) && $__argVarType == 'object') {
                            // class type check
                            $__paramClassName = "N/A";
                            if ($__paramClass)
                                $__paramClassName = $__paramClass->getName();
                            if ($__paramClassName != get_class($__argVar)) {
                                $__argsFit = false;
                            }
                        }
                    }
                    if ($__argsFit) {
                        call_user_func_array(array($this, $__method_name), $__get_arguments);
                        return;
                    }
                }
            }
        }
        throw new Exception("No matching constructors");
    }
}

// how to use multiple constructors
class A extends MultipleConstructors {
    public $value;

    function __constructB(array $hey) {
        $this->value = 'Array#'.count($hey).'<br/>';
    }
    function __construct1(X $first) {
        $this->value = $first .'<br/>';
    }

    function __construct2(Y $second) {
        $this->value = $second .'<br/>';
    }
    function __constructA($hey) {
        $this->value = $hey.'<br/>';
    }

    function __toString() {
        return $this->value;
    }
}

$x = new X("foo");
$y = new Y("bar");

$aa = new A(array("one", "two", "three"));
echo $aa;

$ar = new A("baz");
echo $ar;

$ax = new A($x);
echo $ax;

$ay = new A($y);
echo $ay;

결과:

Array#3
baz
Xfoo
Ybar

생성자를 찾을 수 없는 경우 종료 예외 대신 해당 생성자를 제거하고 "빈" 생성자를 허용할 수 있습니다.아니면 네가 좋아하는 거라도.

시그니처가 다른 여러 컨스트럭터를 만들 때 같은 문제에 직면해 있었습니다만, 안타깝게도 PHP는 직접 작성 방법을 제공하지 않습니다.하지만, 나는 그것을 극복할 방법을 찾았다.희망은 너희들에게도 통한다.

    <?PHP

    class Animal
    {

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

        if (method_exists($this, $function = '__construct'.$numberOfArguments)) {
            call_user_func_array(array($this, $function), $arguments);
        }
    }
   
    public function __construct1($a1)
    {
        echo('__construct with 1 param called: '.$a1.PHP_EOL);
    }
   
    public function __construct2($a1, $a2)
    {
        echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
    }
   
    public function __construct3($a1, $a2, $a3)
    {
        echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
    }
}

$o = new Animal('sheep');
$o = new Animal('sheep','cat');
$o = new Animal('sheep','cat','dog');

// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog

여기에 모래알을 넣겠습니다.

저는 개인적으로 클래스의 인스턴스(개체)를 반환하는 정적 함수로 생성자를 추가하는 것을 좋아합니다.다음 코드가 예시입니다.

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

이제 다음과 같이 사용자 클래스의 인스턴스를 만들 수 있습니다.

$person1 = Person::withName('Example');
$person2 = Person::withEmail('yo@mi_email.com');

난 그 코드를 가져왔어:

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

음, 아직 답이 안 보여서 놀랐어요. 제가 출사표를 던지면 어떨까요?

class Action {
    const cancelable    =   0;
    const target        =   1
    const type          =   2;

    public $cancelable;
    public $target;
    public $type;


    __construct( $opt = [] ){

        $this->cancelable   = isset($opt[cancelable]) ? $opt[cancelable] : true;
        $this->target       = isset($opt[target]) ?     $opt[target] : NULL;
        $this->type         = isset($opt[type]) ?       $opt[type] : 'action';

    }
}


$myAction = new Action( [
    Action::cancelable => false,
    Action::type => 'spin',
    .
    .
    .
]);

옵션으로 옵션을 SpleEnum 확장과 같은 자체 클래스로 분리할 수 있습니다.

abstract class ActionOpt extends SplEnum{
    const cancelable    =   0;
    const target        =   1
    const type          =   2;
}

php7의 경우 파라미터 타입도 비교합니다만, 파라미터의 수는 같지만 타입은 다른2개의 컨스트럭터를 가질 수 있습니다.

trait GenericConstructorOverloadTrait
{
    /**
     * @var array Constructors metadata
     */
    private static $constructorsCache;
    /**
     * Generic constructor
     * GenericConstructorOverloadTrait constructor.
     */
    public function __construct()
    {
        $params = func_get_args();
        $numParams = func_num_args();

        $finish = false;

        if(!self::$constructorsCache){
            $class = new \ReflectionClass($this);
            $constructors =  array_filter($class->getMethods(),
                function (\ReflectionMethod $method) {
                return preg_match("/\_\_construct[0-9]+/",$method->getName());
            });
            self::$constructorsCache = $constructors;
        }
        else{
            $constructors = self::$constructorsCache;
        }
        foreach($constructors as $constructor){
            $reflectionParams = $constructor->getParameters();
            if(count($reflectionParams) != $numParams){
                continue;
            }
            $matched = true;
            for($i=0; $i< $numParams; $i++){
                if($reflectionParams[$i]->hasType()){
                    $type = $reflectionParams[$i]->getType()->__toString();
                }
                if(
                    !(
                        !$reflectionParams[$i]->hasType() ||
                        ($reflectionParams[$i]->hasType() &&
                            is_object($params[$i]) &&
                            $params[$i] instanceof $type) ||
                        ($reflectionParams[$i]->hasType() &&
                            $reflectionParams[$i]->getType()->__toString() ==
                            gettype($params[$i]))
                    )
                ) {
                    $matched = false;
                    break;
                }

            }

            if($matched){
                call_user_func_array(array($this,$constructor->getName()),
                    $params);
                $finish = true;
                break;
            }
        }

        unset($constructor);

        if(!$finish){
            throw new \InvalidArgumentException("Cannot match construct by params");
        }
    }

}

사용방법:

class MultiConstructorClass{

    use GenericConstructorOverloadTrait;

    private $param1;

    private $param2;

    private $param3;

    public function __construct1($param1, array $param2)
    {
        $this->param1 = $param1;
        $this->param2 = $param2;
    }

    public function __construct2($param1, array $param2, \DateTime $param3)
    {
        $this->__construct1($param1, $param2);
        $this->param3 = $param3;
    }

    /**
     * @return \DateTime
     */
    public function getParam3()
    {
        return $this->param3;
    }

    /**
     * @return array
     */
    public function getParam2()
    {
        return $this->param2;
    }

    /**
     * @return mixed
     */
    public function getParam1()
    {
        return $this->param1;
    }
}

보다 현대적인 어프로치: 개별 클래스를 하나의 엔티티와 데이터 하이드레이션으로 혼합합니다.따라서 이 경우 다음 두 가지 클래스가 필요합니다.

class Student 
{
   protected $id;
   protected $name;
   // etc.
}
class StudentHydrator
{
   public function hydrate(Student $student, array $data){
      $student->setId($data['id']);
      if(isset($data['name')){
        $student->setName($data['name']);
      }
      // etc. Can be replaced with foreach
      return $student;
   }
}

//usage
$hydrator = new StudentHydrator();
$student = $hydrator->hydrate(new Student(), ['id'=>4]);
$student2 = $hydrator->hydrate(new Student(), $rowFromDB);

또한 이미 자동 엔티티 수화 기능을 제공하는 교리 또는 기타 ORM을 사용해야 합니다.또한 Student와 같은 개체를 만드는 것을 건너뛰기 위해 종속성 주입을 사용해야 합니다.수화기.

PHP 8부터는 명명된 인수를 사용할 수 있습니다.

class Student {

  protected int $id;
  protected string $name;

  public function __construct(int $id = null, string $name = null, array $row_from_database = null) {
    if ($id !== null && $name !== null && $row_from_database === null) {
      $this->id = $id;
      $this->name = $name;
    } elseif ($id === null && $name === null
        && $row_from_database !== null
        && array_keys($row_from_database) === [ 'id', 'name' ]
        && is_int($row_from_database['id'])
        && is_string($row_from_database['name'])) {
      $this->id = $row_from_database['id'];
      $this->name = $row_from_database['name'];
    } else {
      throw new InvalidArgumentException('Invalid arguments');
    }
  }

}

$student1 = new Student(id: 3, name: 'abc');
$student2 = new Student(row_from_database: [ 'id' => 4, 'name' => 'def' ]);

적절한 체크를 통해 잘못된 인수 조합을 배제할 수 있으므로 생성된 인스턴스는 생성자 끝에 있는 유효한 인스턴스입니다(단, 오류는 런타임에만 감지됩니다).

Kris의 최선의 답변(놀랍게도 나의 클래스 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>");  
}

데이터 유형별 호출 생성자:

class A 
{ 
    function __construct($argument)
    { 
       $type = gettype($argument);

       if($type == 'unknown type')
       {
            // type unknown
       }

       $this->{'__construct_'.$type}($argument);
    } 

    function __construct_boolean($argument) 
    { 
        // do something
    }
    function __construct_integer($argument) 
    { 
        // do something
    }
    function __construct_double($argument) 
    { 
        // do something
    }
    function __construct_string($argument) 
    { 
        // do something
    }
    function __construct_array($argument) 
    { 
        // do something
    }
    function __construct_object($argument) 
    { 
        // do something
    }
    function __construct_resource($argument) 
    { 
        // do something
    }

    // other functions

} 

컨스트럭터에 항상 mode와 같은 파라미터를 추가한 후 switch 문을 실행할 수 있습니다.

class myClass 
{
    var $error ;
    function __construct ( $data, $mode )
    {
        $this->error = false
        switch ( $mode )
        {
            'id' : processId ( $data ) ; break ;
            'row' : processRow ( $data ); break ;
            default : $this->error = true ; break ;
         }
     }

     function processId ( $data ) { /* code */ }
     function processRow ( $data ) { /* code */ }
}

$a = new myClass ( $data, 'id' ) ;
$b = new myClass ( $data, 'row' ) ;
$c = new myClass ( $data, 'something' ) ;

if ( $a->error )
   exit ( 'invalid mode' ) ;
if ( $b->error )
   exit ('invalid mode' ) ;
if ( $c->error )
   exit ('invalid mode' ) ;

또, 이 방법을 사용하면, 기능을 추가하고 싶은 경우는, 언제라도 다른 케이스를 switch 스테이트먼트에 추가할 수 있습니다.또한 위의 예에서는, C 를 제외한 모든 데이터가 「something」으로 설정되어 있기 때문에, 클래스내의 에러 플래그가 설정되고 제어가 다시 행해집니다.메인 프로그램으로 돌아가 다음에 무엇을 할지를 결정합니다(이 예에서는 「비활성 모드」라고 하는 에러 메세지와 함께 종료하도록 지시했습니다만, 그 대신에 유효한 데이터가 발견될 때까지 루프백 할 수도 있습니다).

컨스트럭터뿐만 아니라 메서드에서도 사용할 수 있도록 하기 위해 이 메서드를 만들었습니다.

컨스트럭터:

function __construct() {
    $paramsNumber=func_num_args();
    if($paramsNumber==0){
        //do something
    }else{
        $this->overload('__construct',func_get_args());
    }
}

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

it it it it it it라고 부르게 될 __constructN, , , , , , , , , , , , ,를 정의했습니다.Nargs

다음으로 $myObject -> doSomething($arg1, $arg2, ...$argM)

it it it it it it라고 부르게 될 doSomethingM , 한 , , " " " "Marg; arg;

크리스의 답변은 훌륭하지만 버틀 부쿠가 언급했듯이new static()PHP 5.3+입니다.

그래서 이렇게 하겠습니다(크리스의 답변에서 수정).

<?php

class Student
{
    public function __construct() {
        // allocate your stuff
    }

    public static function withID( $id ) {
        $instance = new static();
        $instance->loadByID( $id );
        return $instance;
    }

    public static function withRow( array $row ) {
        $instance = new static();
        $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
    }
}

?>

사용방법:

<?php

$student1 = Student::withID($id);
$student2 = Student::withRow($row);

?>

php.net OOP 문서에서도 유용한 예를 찾았습니다.

언급URL : https://stackoverflow.com/questions/1699796/best-way-to-do-multiple-constructors-in-php

반응형