PHP类和接口的继承都使用extends关键字,PHP类只能继承一个父类(单继承),但是接口和类不同,接口可以实现多继承,可以继承一个或者多个接口。接口要多个继承的话只要用逗号把继承的接口隔开即可。
类的继承
PHP中子类可以继承父类所有的属性和方法,子类可以拓展自己的属性和方法,也可以重写父类的属性和方法。重写时5.2以前参数可以不同(因为PHP没有重载),5.3以后参数个数必须一致,且访问级别必须大于等于父类的方法。final 修饰的方法不可重载。
class Site
{
var $category="父亲";
function display(){
echo $this->category;
}
}
// 子类扩展站点类别
class Child_Site extends Site {
var $category="儿子";
function setCate($par){
$this->category = $par;
}
}
$oneFather=new Site();
$oneFather->display();
$oneChild=new Child_Site();
$oneChild->display();
结果:
父亲儿子
如果子类没有category属性和话会继承父类的category属性,结果就会是父亲父亲
。
子类调用父类构造方法
PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。
<?php
class BaseClass {
function __construct() {
print "BaseClass 类中构造方法" . PHP_EOL;
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct(); // 子类构造方法不能自动调用父类的构造方法
print "SubClass 类中构造方法" . PHP_EOL;
}
}
class OtherSubClass extends BaseClass {
// 继承 BaseClass 的构造方法
}
// 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();
// 调用 BaseClass 构造方法
$obj = new OtherSubClass();
?>
结果
BaseClass 类中构造方法
SubClass 类中构造方法
BaseClass 类中构造方法
访问控制
PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
- public(公有):公有的类成员可以在任何地方被访问。
- protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
- private(私有):私有的类成员则只能被其定义所在的类访问。
对属性的访问控制
类的属性必须被定义为公有,受保护和私有之一。如果变量前面没有var 和访问控制符的话会报错,用var定义默认是public的。
<?php
//PHP_EOL="\n";
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public.PHP_EOL;
echo $this->protected.PHP_EOL;
echo $this->private.PHP_EOL;
}
}
$obj = new MyClass();
echo $obj->public.PHP_EOL; // 这行能被正常执行
#echo $obj->protected; // 这行会产生一个致命错误
#echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// 可以对 public 和 protected 进行重定义,但 private 而不能
protected $protected = 'Protected2';
function printHello()
{
echo $this->public.PHP_EOL;
echo $this->protected.PHP_EOL;
# echo $this->private;//不能继承私有属性
}
}
$obj2 = new MyClass2();
echo $obj2->public.PHP_EOL; // 这行能被正常执行
#echo $obj2->private; // 未定义 private
#echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>
结果:
Public
Public
Protected
Private
Public
Public
Protected2
从以上代码中可以看出,只有公有属性能被对象直接访问,私有属性和受保护属性必须调用方法来使用。继承不能继承父类的私有属性。
方法的访问控制
类的方法默认为公有,类中的方法可以被定义为公有,私有或受保护。
<?php
//PHP_EOL="\n";
class MyClass
{
// 声明一个公有的构造函数
public function __construct() { }
// 声明一个公有的方法
public function MyPublic() { }
// 声明一个受保护的方法
protected function MyProtected() { }
// 声明一个私有的方法
private function MyPrivate() { }
// 此方法为公有
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
#$myclass->MyProtected(); // 这行会产生一个致命错误
#$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行
class MyClass2 extends MyClass
{
// 此方法为公有
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
#$this->MyPrivate(); // 这行会产生一个致命错误
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行
?>
从以上代码可以看出,私有方法不可继承,对象只能调用公有方法,受保护的和私有的方法只能通过公有方法间接调用。
接口
接口是类行为的抽象,指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。
接口中定义的所有方法都必须是公有,这是接口的特性。
接口中只能定义常量(不能静态常量),子类不能重写常量,只能通过 interfaceName::YOUCONST的方式调用,不能通过parent::YOUCONST的方式调用接口的常量。
但是在类中可以定义静态成员变量,子类能重写常量,const 变量可以使用parent::YOUCONST的方式,className::YOUCONST的方式在子类中访问。
<?php
// 声明一个'iTemplate'接口
interface iTemplate
{
const TEST="444";
public function getVariable();
}
// 实现接口
class Template implements iTemplate
{
private $vars = array();
public function getVariable()
{
echo iTemplate::TEST;
}
}
$dd=new Template();
$dd->getVariable();
抽象类
任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
定义为抽象的类不能被实例化。
被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。
抽象类可以定义变量和静态变量以及常量,因为抽象类是对类属性和行为的抽象。
<?php
abstract class AbstractClass
{
var $test=55;
// 强制要求子类定义这些方法
abstract protected function getValue();
// 普通方法(非抽象方法)
public function printOut() {
echo $this->getValue().PHP_EOL,$this->test , PHP_EOL;
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
$class2 = new ConcreteClass2;
$class2->printOut();
?>
结果:
ConcreteClass1
55
ConcreteClass2
55
static关键字
声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
<?php
class Foo {
public static $my_static = 'foo';
static function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . PHP_EOL;
$foo = new Foo();
echo $foo->my_static."对象无妨访问静态属性".PHP_EOL;
echo '类名访问静态方法',Foo::staticValue().PHP_EOL;
print "对象访问静态方法".$foo->staticValue() . PHP_EOL;
?>
结果:
foo
对象无妨访问静态属性
类名访问静态方法foo
对象访问静态方法foo
Final 关键字
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。