PHP 根据父 class 的现有实例创建子 class 的新实例
PHP create new instance of child class based on existing instance of parent class
我知道这会有点奇怪,所以我会尽量简短明了。
我正在为 Grav 开发一个插件。我确定实现我的目标的最有效方法是扩展基础 classes 之一,Pages。
结构看起来像这样:
- index.php 创建一个 grav 实例 class.
- Base grav class 创建 Pages 实例 class 并将其存储为服务。
- grav class 完成加载过程后,index.php 告诉 grav 运行 处理它的服务处理程序。
- PagesProcessor 运行存储页面上的 init() 函数 class。
- PagesProcessor 触发一个事件,表明页面已初始化。
- 插件接收事件。
实际情况如何。
index.php
$grav = Grav::instance(
array(
'loader' => $loader
)
);
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);
};
}
index.php
try {
$grav->process();
}
Grav.php
public function process()
{
foreach ($this->processors as $processor) {
$processor = $this[$processor];
.....
$processor->process();
.....
}
.....
}
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']]));
.....
}
最后,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"。
我知道这会有点奇怪,所以我会尽量简短明了。
我正在为 Grav 开发一个插件。我确定实现我的目标的最有效方法是扩展基础 classes 之一,Pages。
结构看起来像这样:
- index.php 创建一个 grav 实例 class.
- Base grav class 创建 Pages 实例 class 并将其存储为服务。
- grav class 完成加载过程后,index.php 告诉 grav 运行 处理它的服务处理程序。
- PagesProcessor 运行存储页面上的 init() 函数 class。
- PagesProcessor 触发一个事件,表明页面已初始化。
- 插件接收事件。
实际情况如何。
index.php
$grav = Grav::instance( array( 'loader' => $loader ) );
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); }; }
index.php
try { $grav->process(); }
Grav.php
public function process() { foreach ($this->processors as $processor) { $processor = $this[$processor]; ..... $processor->process(); ..... } ..... }
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']])); ..... }
最后,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"。