PHP 的类中,只可以有常量、属性(包括静态属性)和方法。
$this 伪变量
当一个方法在类定义的内部被调用时,有一个可用的伪变量 $this
。$this
代表当前对象(但如果是从第二个对象静态调用时也可能是另一个对象)。
static (静态)关键字
static 关键字可以定义静态方法和属性,也可用于定义静态变量以及后期静态绑定。静态属性通过 self::$myStatic
这样的形式使用,注意不能省略美元符号。
- 静态属性和方法可以不实例化类而直接访问。
- 如果没有指定访问控制,属性和方法默认为公有。
- 由于静态方法不需要通过对象即可调用(也可以通过对象调用),所以伪变量
$this
在静态方法中不可用。可以用self
。 - 静态属性不能通过一个类已实例化的对象来访问,即不可由对象通过
->
操作符来访问。 - 用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。
- 静态变量和静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
<?php
ini_set('display_errors', 'on');
error_reporting(E_ALL);
class A {
static $static1 = '666';
static function f() {
echo self::$static1;
}
}
echo '|'.A::$static1.'|';
echo A::f();
$a = new A();
echo $a->static1; // Undefined property
类常量
定义和使用常量的时候不需要使用 $
符号。类常量的值始终不变。
<?php
ini_set('display_errors', 'on');
error_reporting(E_ALL);
class A {
const constant = 'constant value';
function f() {
echo self::constant;
}
}
echo '|'.A::constant.'|';
$a = new A();
echo $a::constant;
echo $a->f();
继承
一个类可以在声明中用 extends 关键字继承另一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。PHP不支持多重继承,一个类只能继承一个基类。
除非使用了自动加载,否则一个类必须在使用之前被定义。如果一个类扩展了另一个,则父类必须在子类之前被声明。
构造函数
具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
析构函数
析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。
析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。
属性和方法的访问控制(可见性)
参考:http://php.net/manual/zh/language.oop5.visibility.php
访问控制的关键字有 public(公有),protected(受保护)和 private(私有)。
- public:公有的类成员,可以在任何地方被访问。
- protected:受保护的类成员,可以被其自身以及其子类和父类的内部访问。
- private:私有的类成员,只能被其定义所在的类内部访问。
(1)属性的访问控制
类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。
class MyClass {
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
}
$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
class MyClass2 extends MyClass{
function fun() {
echo $this->public; // 这行能被正常执行
echo $this->protected; // 这行能被正常执行
echo $this->private; // 这行会产生一个致命错误
}
}
$obj2 = new MyClass2();
$obj2->fun();
类属性定义为公有后,可以在类外部随意更新(值、类型),可能会在使用属性的时候导致错误。因此,最好将属性封装为私有或受保护的,然后留接口(方法)供外部读取或设置属性值,在赋值前进行合法性判断等处理操作。
(2)方法的访问控制
类中的方法可以被定义为公有,私有或受保护。没有设置关键字时默认为公有。
类中只有声明为 public 的方法,可以在类的外部随意调用。
父类中声明为 public 和 protected 的方法,子类会自动继承。
(3)其他对象的访问控制
同一个类的对象即使不是同一个实例也可以互相访问对方的私有与受保护成员。
class Father {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function f(Father $o) {
echo $o->name;
}
}
class Son1 extends Father {
}
class Son2 extends Father {
}
$s1 = new Son1("jack");
$s1->f(new Son2("rose"));