博客来自《深入PHP 面向对象、模式与实践》第三版
类中的元素可以被声明为public、private或protected。
在任何地方都可以访问public属性和方法。
只能在当前类中才能访问private方法或属性,即使在子类中也不能访问
//注:在继承中,子类默认继承了父类所有的public和protected方法(但是没有继承private方法或属性)
可以在当前类或子类中访问protected方法或属性,其他外部代码无权访问
这对我们有什么用吗?可见性关键字允许我们只公开类中客户需要的部分,这给对象设置了一个清晰的接口。
通过阻止客户访问特定的属性,访问控制也有助于预防代码中的bug。例如,我们想要在ShopProduct对象支持打折功能,可以增加$discount属性和setDiscount方法。
//ShopDiscount类
public $dicount=0;
//···
function setDiscount($num)
{
$this->discount=$num;
}
除了通过setDiscount设置折扣量,还可以创建getPrice()方法来获取已经实施的折扣。
//ShopProduct类
function getPrice()
{
return ($this->price------$this->discount)
}
这里有个问题。我们只想公开调整过的价格,但是客户也可以很容易的绕过getPrice()方法来访问$price属性:
print $product1->price;
源码
ShopProduct类
class ShopProduct{
public $title;
public $producerMainName;
public $producerFirstName;
public $price;
//设置属性
public $discount=0;
function __construct($title,$producerMainName,$producerFirstName,$price)
{
$this->title=$title;
$this->producerMainName=$producerMainName;
$this->producerFirstName=$producerFirstName;
$this->price=$price;
}
public function getSummaryLine()
{
$base=$this->title."($this->producerMainName)";
$base.=$this->producerFirstName;
return $base;
}
public function getProducer()
{
return "{$this->producerFirstName}"."{$this->producerMainName}";
}
//添加了打折的方法
public function setDiscount($num)
{
$this->discount=$num;
}
//添加获取实施折扣的方法
public function getPrice()
{
return $this->price---$this->discount;
}
}
BookProduct书类
class BookProduct extends ShopProduct {
public $numPages;
public function __construct($title, $producerMainName, $producerFirstName, $price,$numPages)
{
parent::__construct($title, $producerMainName, $producerFirstName, $price);
$this->numPages=$numPages;
}
public function getNumberOfPages()
{
return $this->numPages;
}
public function getSummaryLine()
{
$base=$this->title."($this->producerMainName)";
$base.=$this->producerFirstName;
$base.=":page count-{$this->numPages}";
return $base;
}
}
实例化类
include "3.5.1.php";
$product2=new BookProduct("Exile on Coldharbour Lane","The","Alabama 3",12,60.33);
print $product2->price;//能绕过getPrice方法来访问price是因为price是public属性,可供外面任何地方调用。
这里将输出原始的价格,而不是希望展示折扣价。我们可以通过将$price属性设置为private来禁止直接输出。
这样做可以阻止直接访问,强制客户使用getPrice()方法。任何试图从ShopProduct类外访问$price属性的操作都将失败。对于类外面的世界来说,这个属性就像不存在一样。
设置属性为private有时是一种过于严格的方案,因为private属性不能被子类访问。假设我们的商业规则是只有书不能打折,这时可以覆写getPrice()方法,让它返回$price属性,并且不进行折扣计算
//BookProduct类
public function getPrice()
{
return $this->price;
}
由于在ShopProduct类中而不是BookProduct类中声明属性$price为private,所以这里无法访问这个属性。解决办法是声明$price为protected,让子类也可以访问。
要记住的是,protected属性或方法不可能在声明它的类层次之外被访问。protected属性和方法只能在被定义的类中或者该类的子类中被访问。