PHP 根据父 class 的现有实例创建子 class 的新实例

PHP create new instance of child class based on existing instance of parent class

我知道这会有点奇怪,所以我会尽量简短明了。

我正在为 Grav 开发一个插件。我确定实现我的目标的最有效方法是扩展基础 classes 之一,Pages。

结构看起来像这样:

实际情况如何。

  1. index.php

    $grav = Grav::instance(
        array(
            'loader' => $loader
        )
    );
    
  2. Grav.php

    protected static $diMap = [
        .....
        'pages' => 'Grav\Common\Page\Pages',
        'pagesProcessor' => 'Grav\Common\Processors\PagesProcessor',
        .....
    ];
    
    protected $processors = [
        .....
        'pagesProcessor',
        .....
    ];
    
    public static function instance(array $values = [])
    {
        if (!self::$instance) {
            self::$instance = static::load($values);
        .....
        return self::$instance;
    }
    
    protected static function load(array $values)
    {
        $container = new static($values);
        .....
        $container->registerServices($container);
    
        return $container;
    }
    
    protected function registerServices()
    {
        foreach (self::$diMap as $serviceKey => $serviceClass) {
            .....
            $this->registerService($serviceKey, $serviceClass);
            .....
        }
    }
    
    protected function registerService($serviceKey, $serviceClass)
    {
        $this[$serviceKey] = function ($c) use ($serviceClass) {
            return new $serviceClass($c);
        };
    }
    
  3. index.php

    try {
        $grav->process();
    } 
    
  4. Grav.php

    public function process()
    {
        foreach ($this->processors as $processor) {
            $processor = $this[$processor];
            .....
                $processor->process();
            .....
        }
        .....
    }
    
  5. PageProcessor.php

    public function __construct(Grav $container)
    {
        $this->container = $container;
    }
    public function process()
    {
        .....
        $this->container['pages']->init();
        $this->container->fireEvent('onPagesInitialized', new Event(['pages' => $this->container['pages']]));
        .....
    }
    
  6. 最后,Plugin.php

    public static function getSubscribedEvents()
    {
        return [
            'onPagesInitialized' => ['onPagesInitialized', 0]
        ];
    }
    
    public function onPagesInitialized(Event $event) {
        // Do things here...
    }
    

呼...好的。

现在我想做的是扩展 Pages.php(上面未列出),这样我就可以修改它的一些受保护的属性,这些属性本身没有 setter。问题是,在它被初始化之前,没有办法告诉 grav 使用扩展方法。

我总是可以为我的扩展 class 创建一个新实例,对其进行初始化,然后覆盖现有实例,但这意味着有效地强制初始化两次,这意味着处理时间加倍,这非常低效.

我想做的是类似下面的事情:

Pages.php <- 我无法更改:

class Pages
{
    protected $grav;

    protected $instances;

    protected $children;

    protected $routes = [];

    public function __construct(Grav $c)
    {
        $this->grav = $c;
    }
    .....
    public function init()
    {
        .....
        $this->instances = [];
        $this->children = [];
        $this->routes = [];

        $this->buildPages();
    }
    .....

PagesExtended.php <- 我的 class

class PagesExtended extends Pages
{
    public function __construct(Pages $original)
    {
        // set the properties of this class to the original instance
        parent = $original;
    }

    public function setInstances(Array $newInstances){
        $this->instances = $newInstances;
    }
    .....
}

然后在我的Plugin.php

public function onPagesInitialized(Event $event) {
    // Do things here...
    $this->grav['pages'] = new PagesExtended($event['pages']);
}

我唯一能想到的就是某种 __call 技巧。

那么……有什么想法吗?

编辑------------------------

嗯...我仍然想知道这是否可以完成,但事实证明 grav "freezes" 这些服务无法被覆盖.....不是很开心吧现在。

我不知道你真正想要实现什么,但是你的 Page 自定义方法必须 return 一些东西并且它们在 Twig 中使用。

我经常把Page的自定义数据放到页眉中。在我的插件中,它获取自定义数据 ($oldHeader = $page->header()),计算内容并将最终结果作为自定义新属性再次添加到 Page 对象 ($page->header($newHeader)),然后在 Twig 中我可以访问并打印出来我页面的这些新数据 ({{ page.header.data_generated_in_plugin }}).

这样我就可以在不覆盖页面的情况下做任何事情 class。

事实证明,无论我尝试扩展什么 类,我尝试做的事情在重力环境中都是不可能的。它永远无法通过插件完成,因为那些 类 是 grav."frozen"。