A similar question discusses __construct
,但我将其留在我的标题中,以便搜索找到此人的人。
显然,__ get和__set采用的参数是获取或设置的变量。但是,您必须知道变量名称(例如,知道该人的年龄是$ age而不是$ myAge)。所以,如果您必须知道变量名称,我不明白这一点,特别是如果您正在使用您不熟悉的代码(例如库)。
答案 0 :(得分:6)
This page可能会有用。 (注意你所说的不正确 - __set()
将变量的名称和值作为参数。__get()
只取变量的名称。)
__get()
和__set()
在您希望提供对变量的通用访问的库函数中很有用。例如,在ActiveRecord类中,您可能希望人们能够将数据库字段作为对象属性进行访问。例如,在Kohana PHP框架中,您可以使用:
$user = ORM::factory('user', 1);
$email = $user->email_address;
这是使用__get()
和__set()
完成的。
使用__call()
时可以实现类似的功能,即您可以检测到有人在调用getProperty()和setProperty()并进行相应处理。
答案 1 :(得分:5)
__ get(),__ set()和__call()是PHP所谓的“魔术方法”,这是一个绰号我觉得有点傻 - 我认为“钩子”更容易。无论如何,我离题了......
这些的目的是为访问对象上不的数据名称(属性或方法)提供执行案例,可用于各种“聪明”的思考如变量隐藏,消息转发等
但是有一个成本 - 调用它们的调用比定义的数据库调用慢大约10倍。
答案 2 :(得分:3)
重新定义__get
和__set
在核心课程中尤其有用。例如,如果您不希望您的配置被意外覆盖,但仍希望从中获取数据:
class Example
{
private $config = array('password' => 'pAsSwOrD');
public function __get($name)
{
return $this->config[$name];
}
}
答案 3 :(得分:2)
魔术方法的另一个有用的应用,特别是__get
和__set
以及__toString
是模板。只需编写使用魔术方法的简单适配器,就可以使代码独立于模板引擎。如果您想要移动到另一个模板引擎,只需更改这些方法。
class View {
public $templateFile;
protected $properties = array();
public function __set($property, $value) {
$this->properties[$property] = $value;
}
public function __get($property) {
return @$this->properties[$property];
}
public function __toString() {
require_once 'smarty/libs/Smarty.class.php';
$smarty = new Smarty();
$smarty->template_dir = 'view';
$smarty->compile_dir = 'smarty/compile';
$smarty->config_dir = 'smarty/config';
$smarty->cache_dir = 'smarty/cache';
foreach ($this->properties as $property => $value) {
$smarty->assign($property, $value);
}
return $smarty->fetch($this->templateFile);
}
}
这种方法的隐藏好处是您可以将View对象嵌套在另一个内:
$index = new View();
$index->templateFile = 'index.tpl';
$topNav = new View();
$topNav->templateFile = 'topNav.tpl';
$index->topNav = $topNav;
在index.tpl
中,嵌套看起来像这样:
<html>
<head></head>
<body>
{$topNav}
Welcome to Foobar Corporation.
</body>
</html>
只要echo $index;
答案 4 :(得分:1)
我认为你的代码设计很糟糕。如果您知道并做好设计,则无需在代码中使用__set()
和__get()
。阅读代码非常重要,如果您使用的是工作室(例如Zend工作室),__set()
和__get()
则无法看到您的类属性。
答案 5 :(得分:1)
PHP允许我们动态创建类变量,这可能会导致问题。您可以使用__set和__get方法来限制此行为。请参见下面的示例...
class Person {
public $name;
public function printProperties(){
print_r(get_object_vars($this));
}
}
$person = new Person();
$person->name = 'Jay'; //This is valid
$person->printProperties();
$person->age = '26'; //This shouldn't work...but it does
$person->printProperties();
为了防止上述情况,你可以这样做..
public function __set($name, $value){
$classVar = get_object_vars($this);
if(in_array($name, $classVar)){
$this->$name = $value;
}
}
希望这会有所帮助......
答案 6 :(得分:0)
他们是做“聪明”的事情。
例如,您可以使用__set()
和__get()
与数据库通信。您的代码将是:$myObject->foo = "bar";
,这可能会在后台更新数据库记录。当然你必须对此非常小心,否则你的表现会受到影响,因此引用“聪明”:)
答案 7 :(得分:0)
Overloading方法特别有用。在访问不存在的属性时调用__get(),在尝试编写不存在的属性时调用__set(),并在调用不存在的方法时调用__call()。
例如,假设有一个管理您的配置的类:
class Config
{
protected $_data = array();
public function __set($key, $val)
{
$this->_data[$key] = $val;
}
public function __get($key)
{
return $this->_data[$key];
}
...etc
}
这使得读取和写入对象变得更加容易,并且允许您在读取或写入对象时使用自定义功能进行更改。 例如:
$config = new Config();
$config->foo = 'bar';
echo $config->foo; // returns 'bar'
答案 8 :(得分:0)
使用它们的一个很好的理由是注册系统(我认为Zend Framework将其实现为注册表或配置类iirc),因此您可以执行以下操作:
$conf = new Config();
$conf->parent->child->grandchild = 'foo';
这些属性中的每一个都是自动生成的Config对象,类似于:
function __get($key) {
return new Config($key);
}
显然如果$ conf-&gt; parent已存在,则不会调用__get()方法,因此使用它来生成新变量是一个很好的技巧。
请记住我刚才引用的代码不是功能,我只是为了举例而快速编写代码。
答案 9 :(得分:0)
可能不是世界上最干净的设计,但我遇到的情况是我有很多代码引用了类中的实例变量,即:
$obj->value = 'blah';
echo $obj->value;
但后来,我想在某些情况下设置“value”时做一些特别的事情,所以我重命名了value变量并用我需要的更改实现了__set()和__get()。
其余的代码并不知道区别。