arrays - Dynamically instantiating classes using the Decorator pattern in PHP -
typically, when working decorator pattern, instantiate classes directly, 1 within other:
abstract class handler { public function __construct(handler $handler = null) { $this->handler = $handler; } abstract public function handle(); } class firsthandler extends handler { public function handle() { // calls next guy in chain. obviously, isn't doing anything, it's example sake. $this->handler->handle(); } } // ... , on secondhandler, thirdhandler, fourthhandler $chain = new firsthandler( new secondhandler( new thirdhandler( new fourthhandler() ) ) ); $chain->handle();
however, possibility of chain growing say, perhaps, 20 handlers, can see code begin indent far , makes difficult read, if different handlers in chain don't have names simple "firsthandler", "secondhandler", overall, doesn't good.
i wondering if there way dynamically instantiate classes placing them in array, , iterating down array , passing n+1 element in array constructor argument nth element in array.
i had kind of in mind:
$chain = null; $links = [ firsthandler::class, secondhandler::class, thirdhandler::class, fourthhandler::class ]; foreach ($links $index => $link) { $chain = new $link(new $links[$index + 1]()); }
you might able tell first problem $chain
gets overridden on each call. second problem loop, still have pass each handler chain manually, , doing creating chain original way 4 times, worse. , third problem out of bounds exception.
is there way instantiate chain dynamically demonstrated in intention (perhaps recursive call of sorts) or doomed way doing before?
here's example of using array in constructor, , making use of array_shift
remove first item off list. handler::makechain( $classes )
gets ball rolling...
class handler { private $handler; public function __construct( $chain ) { if( empty( $chain ) === false ) { $this->handler = static::makechain( $chain ); } } public static function makechain( $chain ) { $class = array_shift( $chain ); return new $class( $chain ); } } class firsthandler extends handler{} class secondhandler extends handler{} class thirdhandler extends handler{} class fourthhandler extends handler{} $classes = array( 'firsthandler', 'secondhandler', 'thirdhandler', 'fourthhandler', ); $handler = handler::makechain( $classes ); var_dump( $handler ); // object(firsthandler)#77 (1) { // ["handler":"handler":private]=> // object(secondhandler)#78 (1) { // ["handler":"handler":private]=> // object(thirdhandler)#79 (1) { // ["handler":"handler":private]=> // object(fourthhandler)#80 (1) { // ["handler":"handler":private]=> // null // } // } // } // }
2nd version __construct typehint
class handler { private $handler; public function __construct( handler $injectedhandler = null ) { if( $injectedhandler ) { $this->handler = $injectedhandler; } } public static function handlerfactory( $chain ) { $instance = null; foreach( array_reverse( $chain ) $class ) { $instance = new $class( $instance ); } return $instance; } } class firsthandler extends handler{} class secondhandler extends handler{} class thirdhandler extends handler{} class fourthhandler extends handler{} $classes = array( 'firsthandler', 'secondhandler', 'thirdhandler', 'fourthhandler', ); $handler = handler::handlerfactory( $classes ); var_dump( $handler );
Comments
Post a Comment