您当前的位置:首页 > 网站建设笔记 >

PHP 控制对类成员的访问

来源:PHP 5范例代码查询辞典0
<?php
class Bird
{
	function __construct($name="No-name", $breed="unknown", $price=15)
	{
		$this->name = $name;
		$this->breed = $breed;
		$this->price = $price;
	}
	function setName($name) { $this->name = $name; }
	function setBreed($breed) { $this->breed = $breed; }
	function setPrice($price) { $this->price = $price < 0 ? 0 : $price; }

	function getName() { return $this->name; }
	function getBreed() { return $this->breed; }
	function getPrice() { return $this->price; }

	function display() {
		printf("<p>%s is a %s and costs \$%.2f</p>\n", $this->name, $this->breed, $this->price);
	}
}
?>

下面来创建Bird的一个新实例。假设在写这个例子之前,这个宠物商店已经卖掉了鹦鹉Polynesia,所以,这一次来创建一个喜鹊。首先,调用构造函数,并指定一些合理的值:

$magpie = new Bird("Malaysia", "magpie", 7.5);

$magpie->display();

由于邻居家的猫一直虎视眈眈要除掉这只喜鹊(这可能意味着需要花钱将它放生),试着使用setPrice()将这个喜鹊的价格设置为一个负数:

$magpie->setPrice(-14.95);

$magpie->display();

setPrice()方法不允许将价格设置为小于0的值:

Malaysia is a magpie and costs $0.00

不过,还是有可能绕过这个限制,有可能只是无意,也有可能是一个特别诡异而且憎恨喜鹊的猫科黑客故意所为:

$magpie->price = -14.95;

$magpie->display();

可以看到,输出如下:

Malaysia is a magpie and costs $-14.95

如何制止这种情况发生呢?办法是利用PHP的一个特性,研究过Java的人应该对这个特性很熟悉,但在PHP 5中这是一个新增的特性,即可见性(visibility)。利用可见性,可以通过3个关键字控制类成员的访问:

  • public,声明为public的属性或方法可以被任何其他代码访问。这是PHP 5中所有类成员的默认可见性(注意,在PHP 4中,所有类成员的可见性都是public)。
  • private,private类成员只能从该类内部访问。如果试图从类外部访问,将产生一个错误。
  • protected,声明为protected的类成员可以从该类内部访问,也可以从扩展该类的所有子类中访问。

既然了解了可见性,解决前面遇到的问题就很简单了。只需将以下代码插入到Bird类中构造函数定义的前面即可:

private $name;
private $breed;
private $price;

在浏览器中重新加载这个例子,你会看到下面的结果:

Malaysia is a magpie and costs $7.50

Malaysia is a magpie and costs $0.00

Fatal error: Cannot access private property Bird::$price in /home/www/php5/bird-7.php on line 60

将实例变量声明为private,要求你(或者使用Bird类的其他人)只能通过所定义的设置方法来设置其属性,这样就可以确保一定遵循对这些属性值所做的限制。

所有类成员的可见性都默认为public,这一点当然没什么问题,而且(不同于Java或C++)并不要求专门声明公共变量,不过为所有变量声明可见性仍不失为一个好的做法。一方面,从组织的角度看这样很有好处(例如,如果你习惯提前声明所有变量,那么以后就会发现很可能偶尔需要重用其中的某个变量);另一方面,要想使用私有和保护变量,唯一的办法就是进行显式声明。

使用静态成员和self关键字

有时,你可能希望在类的上下文中访问一个变量或方法,而不是在对象(类实例)中访问。为此,可以使用static关键字,这是PHP 5新增的一个关键字。

举个例子,为上例中的Bird类增加一个静态属性和一个静态方法。用什么顺序来声明关系不大,不过我们倾向于先列出类的所有静态成员,所以下面把新代码直接插入到类声明开始处大括号的后面。

public static $type = "bird";

public static function fly($direction="around") {
    printf("<p>The bird is flying %s</p>\n", $direction);
}

注意,静态成员与其他类成员的可见性是一样的,如果未作声明,它们的可见性也默认为public。可以把static关键字放在可见性关键字的前面,也可以放在其后面,不过一般约定是先声明可见性。静态方法可以有参数,可以返回值,而且可以有默认参数,从这一点上看,它与其他方法没有什么不同。不过,静态方法和静态属性并非与类的具体实例关联,而是与类本身关联。可以使用类名和::操作符在调用代码中引用这些静态成员。例如:

printf("<p>The Bird class represents a %s</p>\n", Bird::$type);

Bird::fly();
Bird::fly("south");

要从类的一个实例访问静态成员,必须另外做点工作。下面对display()方法稍做修改来说明这一点:

<?php
class Bird {
  public static $type = "bird";

  public static function fly($direction="around") {
    printf("<p>The bird is flying %s</p>\n", $direction);
  }
  private $name;
  private $breed;
  private $price;

  public function __construct($name="No-name", $breed="unknown", $price=15) {
    $this->name = $name;
    $this->breed = $breed;
    $this->price = $price;
  }

  function setName($name) { $this->name = $name; }
  function setBreed($breed) { $this->breed = $breed; }
  function setPrice($price) { $this->price = $price < 0 ? 0 : $price; }
 
  function getName() { return $this->name; }
  function getBreed() { return $this->breed; }
  function getPrice() { return $this->price; }

  public function display() {
    printf("<p>The %s named '%s' is a %s, and costs \$%.2f</p>\n", self::$type, $this->name, $this->breed, $this->price);
  }
}
?>

下面创建Bird的一个新实例,看看做上述修改后会有什么作用。代码如下:

$sam = new Bird("Toucan Sam", "toucan");
$sam->display();

以下是修改了display()方法后的输出:

The bird named 'Toucan Sam' is a toucan and costs $15.00

如果查看这个新版本的display()方法,你可能会注意到一个新的关键字self,这个关键字指示类本身。注意不要把self与this混淆,这一点很重要:this的含义是“当前对象”或“类的当前实例”,而self表示“当前类”或“当前对象所属的类”,二者的区别如下。

self关键字有以下要求:

  • 表示一个类。
  • 前面决不能有美元符($)。
  • 后面要有::操作符。
  • 操作符后面的变量名总有一个美元符($)。例如self::$type。

this关键字的要求如下:

  • 表示一个对象或类的一个实例。
  • 前面总有一个美元符($)。
  • 后面跟有->操作符。
  • 操作符后面的变量名不能有美元符($)。例如$this->name。
顶部中部底部