只是一个简单的问题。我见过很多代码实现如下的情况:
class User
{
private $id;
private $firstname;
private $lastname;
public function __construct() { some code }
public function getId() { return $this->id; }
public function getFirstname() { return $this->firstname; }
public function setFirstname($value) { $this->firstname = $value; }
}
// And properties are accessed like:
$user->getFirstname();
$user->getId();
那么使用私有属性和拥有公共getter的原因是什么,而不是公开属性并直接访问它们,如:
$user->firstname;
PS:如果我使用第二种方法可以吗?
修改
在问这个问题之前似乎我没有好好研究(猜测我使用了错误的键来搜索主题)。这是(几乎)同一个问题的另一个好答案:https://stackoverflow.com/a/1568230/1075534
基本上,对于我的情况,使用getter和setter的一个很好的理由是避免更改250个直接访问该属性的类。例如,假设我没有使用吸气剂:
class User
{
public $firstname = 'abc';
public $lastname = 'cde';
}
$user = new User();
echo $user->firstname . ' ' . $user->lastname;
现在,想象一下,我想改变我的应用程序的行为,并决定将名称打印为大写。在这种情况下,我会搜索每个实现(在这种情况下为250)并在我调用属性的任何地方大写输出。但是,如果我使用了getter,那么我只需更改getter方法:
class User
{
private $firstname = 'abc';
private $lastname = 'def';
public getFirstname()
{
return ucfirst(strtolower($this->firstname));
}
public getLastname()
{
return ucfirst(strtolower($this->lastname));
}
}
另外,请记住,getter可能不仅从单个属性收集信息。想象一下:
class User
{
private $firstname = 'abc';
private $lastname = 'def';
public function getName()
{
return $this->firstname . ' ' . $this->lastname;
}
}
对于那些仍然对这个问题有疑问的人,我建议他们阅读戈登提供的材料,特别是我已经联系到的答案。
答案 0 :(得分:9)
使用访问者满足Uniform Access Principle。
引用维基百科:
统一准入原则由Bertrand Meyer提出。它声明“模块提供的所有服务都应该通过统一的符号提供,不会背叛它们是通过存储还是通过计算实现的。”该原理通常适用于面向对象的编程语言。在更简单的形式中,它声明使用属性,预计算属性或方法/查询之间应该没有区别。
在他的博客Fowler explains
中它实际上意味着该人的客户既不知道也不关心年龄是否存储或计算。这使得人物对象可以灵活地在两者之间进行切换,并且从客户端移除通常不必要的问题。它是封装的一个重要部分 - 或者至少是封装的数据隐藏方面。
为了说明这一点,想象一下这样的一个类:
class Now
{
public $timestamp;
public function getTomorrow()
{
return strtotime('+1 day', $this->timestamp);
}
// … more code
当您这样做时,您正在强制开发人员使用该类来了解实现细节。要获得现在的时间戳,开发人员必须
echo $now->timestamp;
然而要获得明天的计算时间戳,开发人员必须
echo $now->getTomorrow();
但开发人员不需要关心,因此如果您想要遵循UAP,您将提供一个Accessor来获取时间戳。并通过方法汇集所有访问权限。
这样做还具有更稳定的API的额外好处。想象一下,您需要在项目的后期更改实现细节,并将时间戳转换为DateTime对象。你的班级现在看起来像这样:
class Now
{
public $dateTime; // <-- no longer just a timestamp
public function getTomorrow()
{
return strtotime('+1 day', $this->dateTime->getTimestamp());
}
// … more code
现在,以前使用$now->timestamp
的任何开发人员都必须更改其使用代码以适应该更改。虽然从一开始就使用了Getter,但它根本不是问题,因为Getter会确保它返回时间戳。为了进一步证明这一点,请注意开发人员如何不必更改任何内容以使用getTomorrow()
。虽然我们在内部更改了细节,但公共API的行为仍然相同。
请注意,UAP只是一个指导原则。现代IDE使您可以轻松地为您生成Accessors和Mutators,因此很容易理解。但这不是绝对的事实。如果您可以合理地证明不遵守它,那么请不要遵循它并使用公共属性。但这应该是一个明智的决定。
但是,总的来说,you want to avoid Getters(和Setters)无论如何都是just tell your objects what to do。这将使API变得更加纤薄。如果您的API有很多很多Getters,那么您很可能会将对象内部的代码分散到消费者中。
答案 1 :(得分:2)
当变量被声明为public时,可以从任何类访问它,使您作为程序员更容易使用;从而解释了您使用您描述的第二种方法的愿望。但是,出于安全原因,有些变量需要声明为私有(有时也被视为一种好的做法)。事实上,我们声明它们是私有的,只能在自己的类中访问它们。如果您需要在另一个类的函数中使用它们,那么您需要遵循您描述的第一个方法
答案 2 :(得分:2)
使用getter使其成为只读。
(这是唯一的概念差异。一种语言可以轻松地允许根据属性和方法定义接口。命名约定并不是真正的基础。)