Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中使用Decorator模式动态实例化类_Php_Arrays_Design Patterns - Fatal编程技术网

在PHP中使用Decorator模式动态实例化类

在PHP中使用Decorator模式动态实例化类,php,arrays,design-patterns,Php,Arrays,Design Patterns,通常,在使用decorator模式时,我通常直接实例化类,一个在另一个中: abstract class Handler { public function __construct(Handler $handler = null) { $this->handler = $handler; } abstract public function handle(); } class FirstHandler extends Handler {

通常,在使用decorator模式时,我通常直接实例化类,一个在另一个中:

abstract class Handler
{
    public function __construct(Handler $handler = null)
    {
        $this->handler = $handler;
    }

    abstract public function handle();
}

class FirstHandler extends Handler
{
    public function handle()
    {
        // Just calls the next guy in the chain. Obviously, this isn't doing anything, it's just for example sake.
        $this->handler->handle();
    }
}

// ... and so on with the SecondHandler, ThirdHandler, FourthHandler

$chain = new FirstHandler(
    new SecondHandler(
        new ThirdHandler(
            new FourthHandler()
        )
    )
);

$chain->handle();
然而,随着链的可能性越来越大,比如说,20个处理程序,您可以看到代码将开始缩进太多,使其难以阅读,特别是如果链中不同的处理程序没有“FirstHandler”、“SecondHandler”这样简单的名称,但总体来说,它看起来并不好

我想知道是否有一种方法可以动态实例化这些类,方法是将它们放在一个数组中,然后遍历数组,并将数组中的n+1元素作为构造函数参数传递给数组中的第n个元素

我有这样的想法:

$chain = null;

$links = [
    FirstHandler::class,
    SecondHandler::class,
    ThirdHandler::class,
    FourthHandler::class
];

foreach ($links as $index => $link) {
    $chain = new $link(new $links[$index + 1]());
}
您可能知道第一个问题是,
$chain
在每次调用时都被覆盖。第二个问题是,即使使用循环,我仍然必须手动将每个处理程序传递到链中,而真正要做的就是以原始方式创建链四次,这实际上更糟。第三个问题是,最终我会得到一个越界异常


有没有一种方法可以按照我的意图(可能是某种递归调用)动态实例化此链,或者我注定要像以前那样执行此操作?

下面是一个在构造函数中使用数组的示例,并使用
array\u shift
从列表中删除第一项<代码>处理程序::makeChain($classes)让球滚起来

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

第二个版本,带有_构造类型提示

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 ) as $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 );

下面是一个在构造函数中使用数组并使用
array\u shift
从列表中删除第一项的示例<代码>处理程序::makeChain($classes)让球滚起来

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

第二个版本,带有_构造类型提示

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 ) as $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 );

你要发明依赖注入哈哈。你能举个例子给我演示一下吗?我想了解我是如何做到这一点的。这包括随时可用的组件,如DI容器等。所有的例子都在这里,你将发明依赖注入哈哈。你能举个例子给我演示一下吗?我想了解我是如何做到这一点的。这包括随时可用的组件,如DI容器等。所有的例子都在这里。这是一个非常好的答案,非常接近于解决我的需要。对我来说唯一的问题是,这将要求我提升对构造函数类型提示的限制,我使用构造函数总是确保类型
Handler
的实例总是被传递。请使用
Handler::handlerFactory($classes)
使用
array\u reverse($chain)尝试我的第二个版本
这是一个非常好的答案,非常接近于解决我的需求。对我来说唯一的问题是,这将要求我提升对构造函数类型暗示的限制,我使用构造函数总是确保类型
Handler
的实例总是被传递。请使用
Handler::handlerFactory($classes)
尝试我的第二个版本,使用
array\u reverse($chain)