工作原理:PHP 中的魔术方法并通过逻辑而不是定义来理解它们
How it works: Magic Methods in PHP and understanding them by logic not by definitions
大家好!
我有以下示例(来自 Opencart):
home.php:
<?php
class ControllerCommonHome extends Controller {
public function index() {
$this->document->setTitle($this->config->get('config_meta_title'));
$this->document->setDescription($this->config->get('config_meta_description'));
$this->document->setKeywords($this->config->get('config_meta_keyword'));
if (isset($this->request->get['route'])) {
$this->document->addLink(HTTP_SERVER, 'canonical');
}
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/common/home.tpl')) {
$this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/common/home.tpl', $data));
} else {
$this->response->setOutput($this->load->view('default/template/common/home.tpl', $data));
}
}
}
controller.php:
<?php
abstract class Controller {
protected $registry;
public function __construct($registry) {
$this->registry = $registry;
}
public function __get($key) {
return $this->registry->get($key);
}
public function __set($key, $value) {
$this->registry->set($key, $value);
}
}
我无法通过逻辑过程来理解它是如何工作的:
"document" 和 setTitle(...) 在哪里?
$this->document->setTitle($this->config->get('config_meta_title'));
"config" 和 get(...) 在哪里?
$this->document->setDescription($this->config->get('config_meta_description'));
这是怎么回事?我无法在脑海中看到/想到这个过程......
我可以阅读它,但是在尝试重做时出现空白。
当您引用一个不存在的对象的 property/attribute 时,PHP __get 和 __set 魔术方法实际上会被调用。然后你可以 return 任何你想要的而不是使用 property/attribute 名称作为键(作为参数传递给那些函数)。在上面的例子中,它是 return 基于键(即 property/attribute 名称)从注册表中获取一个对象。
要找到源 "document" 对象,您首先需要了解它是如何在注册表中注册的。这很可能发生在应用程序引导过程中。我不熟悉 OpenCart,但项目会在某个地方注册到注册表中。一旦发现,您将能够看到正在实例化并存储到该注册表中的对象类型。
__set
和 __get
在加载或设置 属性 时调用:
$this->property = 'value'; // calls __set
echo $this->property; // calls __get.
您的 get()
请求由 __call
处理
$this->get('foo'); // calls __call
Object::get('foo'); // calls __callStatic
查看有关魔术方法的文档:http://php.net/manual/en/language.oop5.overloading.php#object.call
同样在您的控制器示例中,任何 __get 或 __set 都被重定向到注册表 class 方法 get
和 set
.
因此,如果在您的示例中 $this 是 class 扩展抽象 class 控制器:
$this->title = 'foo'; // redirected to registry set
echo $this->title; // redirected to registry get
从您发布的代码中,很难确定文档是什么。然而,文档是通过注册表加载的。所以:
// request
$this->document->setTitle('foo');
// calls magic method __get
// calls $this->registry->get('document');
// returns the value in registry for document, which might be an object; let's hope so
// now run the method setTitle('foo') on the object returned from the registry
大家好! 我有以下示例(来自 Opencart):
home.php:
<?php
class ControllerCommonHome extends Controller {
public function index() {
$this->document->setTitle($this->config->get('config_meta_title'));
$this->document->setDescription($this->config->get('config_meta_description'));
$this->document->setKeywords($this->config->get('config_meta_keyword'));
if (isset($this->request->get['route'])) {
$this->document->addLink(HTTP_SERVER, 'canonical');
}
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/common/home.tpl')) {
$this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/common/home.tpl', $data));
} else {
$this->response->setOutput($this->load->view('default/template/common/home.tpl', $data));
}
}
}
controller.php:
<?php
abstract class Controller {
protected $registry;
public function __construct($registry) {
$this->registry = $registry;
}
public function __get($key) {
return $this->registry->get($key);
}
public function __set($key, $value) {
$this->registry->set($key, $value);
}
}
我无法通过逻辑过程来理解它是如何工作的:
"document" 和 setTitle(...) 在哪里? $this->document->setTitle($this->config->get('config_meta_title'));
"config" 和 get(...) 在哪里? $this->document->setDescription($this->config->get('config_meta_description'));
这是怎么回事?我无法在脑海中看到/想到这个过程...... 我可以阅读它,但是在尝试重做时出现空白。
当您引用一个不存在的对象的 property/attribute 时,PHP __get 和 __set 魔术方法实际上会被调用。然后你可以 return 任何你想要的而不是使用 property/attribute 名称作为键(作为参数传递给那些函数)。在上面的例子中,它是 return 基于键(即 property/attribute 名称)从注册表中获取一个对象。
要找到源 "document" 对象,您首先需要了解它是如何在注册表中注册的。这很可能发生在应用程序引导过程中。我不熟悉 OpenCart,但项目会在某个地方注册到注册表中。一旦发现,您将能够看到正在实例化并存储到该注册表中的对象类型。
__set
和 __get
在加载或设置 属性 时调用:
$this->property = 'value'; // calls __set
echo $this->property; // calls __get.
您的 get()
请求由 __call
$this->get('foo'); // calls __call
Object::get('foo'); // calls __callStatic
查看有关魔术方法的文档:http://php.net/manual/en/language.oop5.overloading.php#object.call
同样在您的控制器示例中,任何 __get 或 __set 都被重定向到注册表 class 方法 get
和 set
.
因此,如果在您的示例中 $this 是 class 扩展抽象 class 控制器:
$this->title = 'foo'; // redirected to registry set
echo $this->title; // redirected to registry get
从您发布的代码中,很难确定文档是什么。然而,文档是通过注册表加载的。所以:
// request
$this->document->setTitle('foo');
// calls magic method __get
// calls $this->registry->get('document');
// returns the value in registry for document, which might be an object; let's hope so
// now run the method setTitle('foo') on the object returned from the registry