How to return subclass from constructor in PHP

2019-08-26 05:38发布

问题:

<?php

class Super {
    public $my;
    public function __construct ( $someArg ) {
        if ( class_exists('Sub') ) {    // or some other condition
            return new Sub( $someArg );
        }
        $this->my = $someArg;
    }
}

class Sub extends Super {}

?>

This doesn't work, as new Super() will be an "empty" Super object (all members are NULL). (PHP doesn't allow assignments to $this, so $this = new Sub() doesn't work either).

I know the correct pattern would be a factory here. But that would require a lot of changes in the code, so I'm wondering whether it's possible to do it this way. Since Sub is-a Super, I don't see why it shouldn't be restricted from an OOP point of view.

回答1:

You can't assign to $this and you cannot return anything from a constructor.



回答2:

You got something wrong here. The constructor does not have a return value, you cannot return an instance from the constructor - once the constructor is called, the class is settled, you cannot change it any more.

What you want to do is to implement the factory pattern for this:

<?php

class Super {
    public $my;
    public function __construct ( $someArg ) {
        $this->my = $someArg;
    }

    public static function factory ($somearg) {
        if ( class_exists('Sub') && $somearg["foo"] == "bar") {    // or some other condition
            return new Sub( $someArg );
        }
        else {
            return new Super($someArg);
        }
    }
}

class Sub extends Super {}

$mynewsuborsuper = Super::factory($myargs);
?>


回答3:

Use PHP reflection. No need for switches or inheritance when you're using a factory.

<?php
class DocumentFactory
{
    public function create($className, $constructorArguments = array())
    {
        $reflection = new ReflectionClass($className);
        return $reflection->newInstanceArgs($constructorArguments);
    }
}

abstract class Document
{
    $protected $doc;
    public function __construct($string){$this->doc = $string;}
}

class XMLDocument extends Document
{
    public function __construct($string, $extraArg)
    {
        parent::__construct($string);
        //Do something else with $extraArg
    }
}

class HTMLDocument extends Document
{

}

$DFactory = new DocumentFactory();

$XMLDocument = $DFactory->create('MY\FULL\NAMESPACE\XMLDocument', array(//extra arguments));

//Or add .php at the end if you're not using namespaces


标签: php oop