继承
继承已为大家所熟知的一个程序设计特性,PHP 的对象模型也使用了继承。继承将会影响到类与类,对象与对象之间的关系。
比如,当扩展一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。
继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。
除非使用了自动加载,否则一个类必须在使用之前被定义。如果一个类扩展了另一个,则父类必须在子类之前被声明。此规则适用于类继承其它类与接口。
class MyClass{ protected function myFunc() { echo "MyClass::myFunc()\n"; }
}
class OtherClass extends MyClass{ // 覆盖了父类的定义 public function myFunc() { // 但还是可以调用父类中被覆盖的方法 parent::myFunc(); echo "OtherClass::myFunc()\n"; }
}
$class = new OtherClass();$class->myFunc();/** * 输出结果 -> * MyClass::myFunc() * OtherClass::myFunc() */?>Static(静态)关键字
声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性应用于保存类的共有数据。
静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量$this在静态方法中不可用。静态属性不可以由对象通过 -> 操作符来访问。静态方法里面只能访问静态属性。
用静态方式调用一个非静态方法会导致一个E_STRICT级别的错误。类的内部可以通过self或者static关键字访问自身静态成员。
就像其它所有的 PHP
静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字self,parent或static。可以通过parent关键字访问父类的静态成员,可以通过类的名称在类定义外部访问静态成员。
class Human{
static public $name = "小妹";
public $height = 180;
static public function tell(){
echo self::$name;//静态方法调用静态属性,使用self关键词
//echo $this->height;//错。静态方法不能调用非静态属性
//因为 $this代表实例化对象,而这里是类,不知道 $this 代表哪个对象
}
public function say(){
echo self::$name . "我说话了";
//普通方法调用静态属性,同样使用self关键词
echo $this->height;
}
}
$p1 = new Human();
$p1->say();
$p1->tell();//对象可以访问静态方法
echo $p1::$name;//对象访问静态属性。不能这么访问
$p1->name//因为静态属性的内存位置不在对象里
Human::say();//错。say()方法有$this时出错;没有$this时能出结果
//但php5.4以上会提示
?>数据访问
1.parent关键字可以访问父类中被子类重写的方法。
2.self关键字可以用于访问类自身的成员方法,也可以用于访问自身的静态成员和类常量;不能用于访问自身的属性;使用常量的时候不需要在常量名称前加$符号。
3.static关键字用于访问类自身定义的静态成员,访问静态属性时需要在属性前面添加$符号
}
class ChildClass extends BaseClass{public function a(){echo "a() from ChildClass\n";parent::a(); //访问父类的a方法;self::b(); //访问自身类b方法echo self::MM; //访问自身常量}const MM = "i am constent";private function b(){echo "b() from ChildClass";}
}
$class = new ChildClass();
$class->a();
抽象类
PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。
这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。
abstract class AbstractClass{ // 强制要求子类定义这些方法 abstract protected function getValue(); abstract protected function prefixValue($prefix); // 普通方法(非抽象方法) public function printOut() { print $this->getValue() . "\n"; }
}
class ConcreteClass1 extends AbstractClass{ protected function getValue() { return "ConcreteClass1"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass1"; }
}
class ConcreteClass2 extends AbstractClass{ public function getValue() { return "ConcreteClass2"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass2"; }
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>接口
使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过interface关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
接口中定义的所有方法都必须是公有,这是接口的特性。
要实现一个接口,使用implements操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。实现多个接口时,接口中的方法不能有重名。
接口也可以继承,通过使用 extends 操作符。
类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。接口中也可以定义常量。
接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
// 声明一个'iTemplate'接口
interface iTemplate{ public function setVariable($name, $var); public function getHtml($template);}// 实现接口
// 下面的写法是正确的class Template implements iTemplate{ private $vars = array(); public function setVariable($name, $var) { $this->vars[$name] = $var; } public function getHtml($template) { foreach($this->vars as $name => $value) { $template = str_replace('{' . $name . '}', $value, $template); } return $template; }
}
继承多个接口
interface a{ public function foo();
}
interface b{ public function bar();
}
interface c extends a, b{ public function baz();
}
class d implements c{ public function foo() { } public function bar() { } public function baz() { }
}
?>Trait
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait
为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait
和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
}
class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */
}
class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */
}
?>
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。多个 trait,通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
Final 关键字
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为
final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
Example #1 Final 方法示例
class BaseClass { public function test() { echo "BaseClass::test() called\n"; } final public function moreTesting() { echo "BaseClass::moreTesting() called\n"; }
}
class ChildClass extends BaseClass { public function moreTesting() { echo "ChildClass::moreTesting() called\n"; }
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>
Example #2 Final 类示例
final class BaseClass { public function test() { echo "BaseClass::test() called\n"; } // 这里无论你是否将方法声明为final,都没有关系 final public function moreTesting() { echo "BaseClass::moreTesting() called\n"; }
}
class ChildClass extends BaseClass {}
// 产生 Fatal error: Class ChildClass may not inherit from final class (BaseClass)
?>
以上。
end
文/编辑:atong
排版布局:atong
Time : 2018/2/28
领取专属 10元无门槛券
私享最新 技术干货