系统学习PHP之面向对象(中)

继承

继承已为大家所熟知的一个程序设计特性,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

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180228G07N4X00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券