Php 每个公共属性都必须有访问器方法吗?
我陷入了OOP,我陷入了以下困境。我有一门a课:Php 每个公共属性都必须有访问器方法吗?,php,oop,object,Php,Oop,Object,我陷入了OOP,我陷入了以下困境。我有一门a课: class Recipe { var $title; var $time; var $ingredients = array(); var $instructions; var $category; function __construct($title, $time, $ingredients, $instructions, $category) { $this->ti
class Recipe {
var $title;
var $time;
var $ingredients = array();
var $instructions;
var $category;
function __construct($title, $time, $ingredients, $instructions, $category) {
$this->title = $title;
...
}
function getTitle() {
return $this->title;
}
}
所有属性都是公共的(默认情况下)。我是否必须为所有这些属性(例如getTitle)定义访问器方法,或者我是否可以直接引用这些属性,如下所示:
...
$recipe = new Recipe($title, $time, $ingredients, $instructions, $category);
echo $recipe->title; // versus $recipe->getTitle();
看起来我不用定义访问器方法就能节省很多时间。然而,我想知道这种方法的优缺点是什么?公共属性不需要getter/setter方法,但它使您更容易出错。使用访问器还可以强制数据验证,而直接设置公共属性可以允许设置任何数据 如果您利用PHP的神奇功能,就可以编写一个动态getter/setter方法来访问私有/受保护的属性
<?php
/**
* Implements auto get/set
* class Entity extends GetterSetter {}
* $name = $entity->getName(); // return $this->name;
* $name = $entity->getFullName(); // return $this->full_name;
* $entity->setFullName("Ian"); // $this->full_name = "Ian";
*/
class GetterSetter {
public function __call($name, $args) {
if (substr($name, 0, 3) == "get") {
$key = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', (substr($name, 3, strlen($name)-3))));
if (property_exists($this, $key)) {
//print "/* GET " . $this . "->" . $key . " = " . $this->$key . "\n */";
return $this->$key;
}
} elseif (substr($name, 0, 3) == "set") {
$key = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', (substr($name, 3, strlen($name)-3))));
if (property_exists($this, $key)) {
//print "/* SET " . $this . "->" . $key . " = " . $args[0] . "\n */";
return ($this->$key = $args[0]);
} else {
print "Key not found: " . $this . "->" . $key;
}
}
}
}
?>
OOP的黄金法则是始终将您的财产私有化!在极少数情况下,公共财产是被允许的,但即使如此,也可能有另一种解决方案
原因是:如果你把你的财产公之于众,任何人都可以随意改变它们。大多数属性不能只是任何值。$title属性是否应为整数?我对此深表怀疑。那么,如果您或其他人意外地将其设置为整数,该怎么办?你不会发现的。它将设置该值,并且您的程序将继续运行,直到失败为止,因为某个地方需要一个字符串。此外,在设置属性之前,您的属性可能需要以某种方式进行验证。您将在属性的setter中包含所有这些验证
即使不需要验证属性,也最好将它们放在getter和setter后面,以防最终需要验证它
将属性设置为私有可确保在对象不应受到干扰的情况下不会造成任何混乱,从而避免由此产生的任何错误。:)
有时候你会想“好吧,只有我会编辑我的代码,所以什么都不会发生”。不过,你现在应该练习一下。养成这样做的习惯。以后您将避免任何麻烦。使用getter/setter:
- 您可以更改实现。例如,稍后您可能会更改getTime以计算$instructions的数量,而不是使用成员$time
- setter可以抛出异常、验证输入或新状态、更改其他数据、日志等
将您的对象想象为其他对象希望如何使用它或它应该做什么。对象不仅仅是数据类型的列表。我要说的是,不应该使用不必要的setter/getter加载,尤其是在PHP中,否则应用程序可能会变得非常慢。 下面是一个简单的例子:
<?php
class Recipe {
public $title;
function __construct($title){
$this->title = $title;
}
function getTitle(){
return $this->title;
}
}
$a = new Recipe('potatoes');
$t1 = microtime(true);
for($i=0;$i<1000000;$i++){
$x = $a->title;
}
$t2 = microtime(true) - $t1;
echo $t2.'s<br/>';
$a = new Recipe('potatoes');
$t1 = microtime(true);
for($i=0;$i<1000000;$i++){
$x = $a->getTitle();
}
$t2 = microtime(true) - $t1;
echo $t2.'s<br/>';
?>
回声:
0.25662112236023s
1.0309250354767s
使用getter时速度慢4倍 大多数脚本语言都不支持getter/setter。它们最初是专门用Java和JavaBean引入的。在静态编译的代码中,强封装是有意义的。在脚本语言中,所有访问无论如何都要通过解释器,而不是直接访问内存地址;因此有神奇的方法。在PHP中,您可以通过_; get路由所有内容,从而使包装器变得多余
getter/setter的用例是精心设计的过滤和验证方案。除非你提出一个具体的属性,否则准备空的setter(getter很少转换值)是没有意义的。它有助于通过防止设置任意数据来强制验证和减少错误。我不能只使用_get和_set吗?这很有意义!那么为什么在PHP中所有的属性都默认设置为public而不是private呢?我想首先是因为这意味着你不必在每个方法前面都加上“public”。此外,可能存在后台兼容性问题,要求它保持公开。尽管我似乎找不到任何文档来说明为什么默认情况下它们是公共的。注意,在C++中,默认情况下属性是私有的。当你开始使用一种特定的语言时,请确保你知道它是哪种方式,其中包括可访问性关键字。您当前的风格是PHP4时代,没有人应该在新代码中使用它。@Charles,可访问性关键字这些是什么?我无法在php文档中找到引用。你是说像“设置”还是“获取”这样的魔术方法吗?@mario,我认为应该强调最佳实践,因为OP显然是初学者。教他们封装的价值以及如何实现它,然后说明什么时候可以改变/打破规则,而不是相反。知道什么时候不强调封装比完全不熟悉这个概念要好。如果我正确理解了你的代码,那就相反了。。。getter的速度快了4倍。很抱歉,我按错误的顺序复制了结果,请允许我编辑我的帖子,您可以自己尝试测试:)