为什么我会使用PHP隐藏信息?
<?php
function foo($bar) {
echo $bar;
}
foo('foobar');
?>
VERSUS
<?php
class foo {
private $bar;
function __construct($b){
$this->bar = $b;
}
function display() {
echo $this->bar;
}
}
$foobar = new foo('bar');
$foobar->display();
?>
答案 0 :(得分:7)
无论您发布什么,都会成为您的公共合同。其他人开始依赖你的公共方法,使用它们并期望它们在那里并且工作相同。半年后,“其他人”也许就是你自己。
因此要公开宣传要非常保守。它使您可以自由地发展代码并修复其中的错误,而不会破坏公共接口。
答案 1 :(得分:4)
信息隐藏(封装)是一件好事,因为它减少了客户使用“未记录的”信息的可能性。
封装的全部内容是最小化代码的接口,以便您可以随时更改未发布的位,而不会影响它的客户端。
例如,假设您有一个将一个字符串映射到另一个字符串的字典类。让我们进一步说你实现这是一个快速而肮脏的双阵列解决方案,因为你落后于时间表 - 显然有时会发生这种情况:-)并且你没有封装使用它的数组和方法。
所以,它已经在该领域存在了一段时间,数百万客户已经购买了它。他们中的一半人抱怨速度,因为他们的词典有十万个词条。
另一半是通过背后直接使用内部但未隐藏的数据结构来使用它。
你做什么的?如果你什么都不做,你的50万客户将无法续签合同,他们会对你的产品进行诋毁。
如果您更改代码以使用平衡树或散列,那么其他 50万客户会对您的决定抱怨。
这就是你最终要做的事情。您最终维护两个版本,一个用于大数据用户,另一个用于偷偷摸摸的人。这大大增加了您的成本和工作量。
如果您已正确封装了数据和方法,则可以替换内部批发,而不会对您的任何客户产生任何影响。
答案 2 :(得分:3)
您可以这样做来封装功能并保护使用代码免受更改。举个例子:
class Person
{
protected $legs;
public function setLegs($number){
$this->legs = $number;
}
}
让我们假设我们现在有一些使用这个类的代码......
if ($_POST['legs'])
{
$person = new Person;
$person->setLegs($_POST['legs']);
}
你可以使用以下课程
来完成这项工作class Person
{
public $legs;
}
$ person = new Person; $ person-&gt; legs = $ _POST ['legs'];
如果您需要为腿提供任何验证或者您希望稍后进行更改,则会出现问题。假设您必须更改有关某个人的规则(例如,一个人可以拥有的最大腿数为10) - 如果您还没有封装逻辑,那么您现在需要遍历您的应用程序以查找其用途。 。
class Person
{
protected $legs;
public function setLegs($number){
if ( ! is_int($number) || $number > 10){
throw new Exception('incorrect user input');
}
$this->legs = $number;
}
}
封装非常重要,原因如下:
答案 3 :(得分:3)
你的例子似乎并没有清楚地表明你在问什么。您是否想知道为什么人们会在班级成员身上使用各种保护资格而不仅仅是公开一切?
本质上是封装的概念。将类的外部可见“足迹”视为其“契约”。定义和外部可见的类提供了一些功能。完全如何该类在内部实现功能,与该类之外的任何事情无关。它不仅不需要在类之外被识别,它明确地不应该被知道。
这导致了面向对象设计的进一步概念,称为关注点分离,依赖性反转,开放/封闭原则等。如果是其他类/对象/等。可以直接访问该特定类的所有内部,可以编写代码来使用这些内部。私人会员,私人会员等
这在外部代码和类的内部逻辑之间创建了一个依赖关系,它不应该暴露那个内部逻辑。这使得重新实现该类更加困难,将其与另一个实现相同“契约”(虽然具有不同的内部功能)交换,透明地添加额外的内部功能而不改变“契约”等。
编辑:您可能还想知道为什么人们会创建一个私有成员变量,然后公开一个公共getter和setter来操纵该变量。为什么当你可以把变量公之于众时,为什么要经历那个额外的麻烦,对吗?
嗯,在某些情况下可能没问题。但请记住封装和维护合同的概念。如果您想要更改类的某些内部实现并且变量受到影响该怎么办?也许你需要稍微改变它的类型?如果变量是公开的,特别是在静态类型的环境中(不是PHP,但你明白了),任何这样的变化都将是合同的“突破性变化”。
如果有公共getter / setter方法,你可以根据需要改变私有变量,并在方法中做任何必要的转换或逻辑,基本上保持变化透明。
或许您想要审核对该变量的更改...只需在setter方法中执行(记录,引发事件,无论您需要做什么),而不是无处不在访问公共变量的代码(包括尚未编写的代码)。
将变量设为私有并将其包装在公共getter / setter中的习惯(必要时......并非每个私有成员变量都需要公共访问)是一般维护的好习惯。完全有可能,甚至可能,绝大多数班级成员永远不会超越那种简单的逻辑。但是在相对罕见的情况发生时,使用吸气剂/定位器会更容易很多。
基本上,它是一种设计,基本上只增加了很少的前期代码(一次性创建getter / setter,而不是持续维护成员变量访问),允许您自由地进行更改该类不破坏对象的二进制兼容性并打破其“契约”。
编辑: @mario在评论中提出了一个很好的观点,我想澄清一些事情。肯定不是一个好习惯,始终为所有私人成员编写getter / setter。我们的想法是为成员使用getter / setter,逻辑上应公开。例如,如果类在显示中定义了一段文本,并且由getter / setter修改的成员是字体,大小,重量等。那么您将在逻辑上看到访问方法(在不同的语言中区别对待)设置类的这些属性。
这些属性可以由一个私人成员在内部维护,或由一个或多个成员,或通过其他方式等维护。这是不应该在课堂外公开的部分。班级以外的所有事情都知道“我告诉这个对象要改变它的字体重量。” 不“我告诉此对象将其_font
变量设置为此值。”
另请注意,通过访问者将外部视为成员的内容可能根本不访问私有成员,或者至少不以相同方式访问私有成员。一个很好的例子是只读访问器(getters),它代表对象的某个给定状态。例如,IsValid
可以在模型内部执行各种业务验证逻辑,并返回表示对象状态的bool
。它没有返回某个私有bool
成员的内容。
答案 4 :(得分:2)
例如,在开发库时,您可能希望将类的内部隐藏给API的用户,这样,如果您决定更改类的工作方式,则不必担心会破坏每个人的程序因为他们一直在访问他们不应该访问的成员。您只能看到一个您知道不会改变的界面,这样您就可以安全地修改这些功能的工作方式。