继承
访问控制
Static(静态)关键字
重写
Final关键字
数据访问补充
接口
多态
抽象类
面向对象--继承
继承的好处
父类里面定义的类成员可以不用在子类中重复定义,节约了编程的时间和代价
• 比如,人的吃这个方法一旦在父类中定义,那么NBA球员和女主播两个子类就不需要实现吃这个方法了,就好像天生就有这个功能一样
同一个父类的子类拥有相同的父类定义的类成员,因此外部代码调用它们的时候可以一视同仁
• 比如,一个NBA球员和一个女主播,因为他们都是人,所以可以直接调用父类定义的“吃”方法,而不用管他到底是个NBA球员还是女主播
子类可以修改和调整父类定义的类成员
• 我们称为重写(Overwrite)
• 一旦子类修改了,就按照子类修改之后的功能执行
<?php
date_default_timezone_set("PRC");
class Human{
public $name;
public $height;
public $weight;
public function eat($food){
echo $this->name.".'s eating ".$food."\n";
}
}
class Animal{
}
//在PHP中,可以用extends关键字来表示类的继承,后面跟父类的类名。
//PHP中extends后面只能跟一个类的类名,这就是PHP的单继承原则
class NbaPlayer extends Human{
//定义属性
public $team="Bull";
public $playerNumber="23";
function __construct($name,$height,$weight,$team,$playerNumber){
echo "In NbaPlayer Constructor\n";
$this->name=$name; //父类中的属性,可以通过$this->来访问
$this->height=$height;
$this->weight=$weight;
$this->team=$team;
$this->playerNumber=$playerNumber;
}
function __destruct(){
echo "Destroying ".$this->name."<br/>";
}
//定义方法
public function run(){
echo "Running\n";
}
public function jump(){
echo "Jumping\n";
}
public function dribble(){
echo "Dribbling\n";
}
public function shoot(){
echo "Shooting\n";
}
public function dunk(){
echo "Dunking\n";
}
public function pass(){
echo "Passing\n";
}
}
$jordan = new NbaPlayer("Jordan","198cm","98kg","Bull","23");
echo $jordan->name."\n";
$jordan->eat('Apple'); //在子类的对象上可以直接访问父类中定义的方法和属性
?>
Output:
In NbaPlayer Constructor
Jordan
Jordan.'s eating Apple
Destroying Jordan
面向对象--访问控制
问题
- NBA球员一般都不想别人知道自己的真实年龄怎么办?
面向对象的三种访问权限
• public公有的类成员,可以在任何地方被访问
∘ 定义该成员的类(自身),该类的子类,其他类
• protected受保护的类成员,可以被其自身以及其子类访问
• private私有的类成员,只能被自身访问
(private的类成员只能在类的内部访问)
<?php
date_default_timezone_set("PRC");
class Human{
public $name;
protected $height; //只有自身和子类可以访问
public $weight;
private $isHungry=true; //不能被子类访问
public function eat($food){
echo $this->name.".'s eating ".$food."\n";
}
public function info(){
echo $this->name.";".$this->height.";".$this->isHungry."<br/>";
}
}
class Animal{
}
//在PHP中,可以用extends关键字来表示类的继承,后面跟父类的类名。
//PHP中extends后面只能跟一个类的类名,这就是PHP的单继承原则
class NbaPlayer extends Human{
//定义属性
public $team="Bull";
public $playerNumber="23";
private $age="40"; //private的类成员只能在类的内部被访问
function __construct($name,$height,$weight,$team,$playerNumber){
echo "In NbaPlayer Constructor\n";
$this->name=$name; //父类中的属性,可以通过$this->来访问
$this->height=$height; //在父类是protected,子类里面可以访问
$this->weight=$weight;
$this->team=$team;
$this->playerNumber=$playerNumber;
}
function __destruct(){
echo "Destroying ".$this->name."<br/>";
}
//定义方法
public function run(){
echo "Running\n";
}
public function jump(){
echo "Jumping\n";
}
public function dribble(){
echo "Dribbling\n";
}
public function shoot(){
echo "Shooting\n";
}
public function dunk(){
echo "Dunking\n";
}
public function pass(){
echo "Passing\n";
}
public function getAge(){
echo $this->name."'s age is ".($this->age-2)."<br/>"; //如果不加括号会只打印-2,output是38 (真实年龄是40,38是假年龄)
}
}
$jordan = new NbaPlayer("Jordan","198cm","98kg","Bull","23");
//echo $jordan->age."\n"; //这一句会返回这个错误:Fatal error: Cannot access private property NbaPlayer::$age in /var/www/html/oo.php on line 68
//echo $jordan->height; //这一句会返回这个错误:Fatal error: Cannot access protected property NbaPlayer::$height in /var/www/html/oo.php on line 74
$jordan->getAge();
$jordan->info(); //通过info的方法间接地访问private的isHungry
?>
Output:
In NbaPlayer Constructor
Jordan's age is: 38
Jordan;198cm;1
Destroying Jordan
面向对象--静态成员
问题
- 所有NBA球员都有一个共同的联盟总裁"David Stern"
- 总裁换成了"Adam Silver"怎么办?
• 换是一个动词,所以应该对应类里面的一个方法
使用类的静态成员特性就可以达到这样的效果
- static关键字
>>>>未使用static<<<<<
<?php
date_default_timezone_set("PRC");
class Human{
public $name;
protected $height; //只有自身和子类可以访问
public $weight;
private $isHungry=true; //不能被子类访问
public function eat($food){
echo $this->name.".'s eating ".$food."\n";
}
public function info(){
echo $this->name.";".$this->height.";".$this->isHungry."<br/>";
}
}
class Animal{
}
class NbaPlayer extends Human{
//定义属性
public $team="Bull";
public $playerNumber="23";
private $age="40"; //private的类成员只能在类的内部被访问
public $president = "David Stern";
public function changePresident($newPrsdt){
$this->president=$newPrsdt;
}
function __construct($name,$height,$weight,$team,$playerNumber){
echo "In NbaPlayer Constructor\n";
$this->name=$name; //父类中的属性,可以通过$this->来访问
$this->height=$height; //在父类是protected,子类里面可以访问
$this->weight=$weight;
$this->team=$team;
$this->playerNumber=$playerNumber;
}
function __destruct(){
echo "Destroying ".$this->name."<br/>";
}
//定义方法
public function run(){
echo "Running\n";
}
public function jump(){
echo "Jumping\n";
}
public function dribble(){
echo "Dribbling\n";
}
public function shoot(){
echo "Shooting\n";
}
public function dunk(){
echo "Dunking";
}
public function pass(){
echo "Passing";
}
public function getAge(){
echo $this->name."'s age is ".($this->age-2)."<br/>"; //如果不加括号会只打印-2,output是38 (真实年龄是40,38是假年龄)
}
}
$jordan = new NbaPlayer("Jordan","198cm","98kg","Bull","23");
$james = new NbaPlayer("James","203cm","120kg","Heat","6");
$jordan->changePresident("Adam Silver");
echo "Jordan: ".$jordan->president;
echo "James: ".$james->president;
?>
output:
In NbaPlayer Constructor
In NbaPlayer Constructor
Jordan: Adam Silver
James: David Stern
Destroying James
Destroying Jordan
>>>>使用static<<<<<
<?php
date_default_timezone_set("PRC");
/**
* 1. 静态属性用于保存类的公有数据
* 2. 静态方法里面只能访问静态属性
* 3. 静态成员不需要实例化对象就可以访问
* 4. 类的内部可以通过self或者static关键字访问自身静态
* 5. 可以通过parent关键字访问父类的静态成员
* 6. 可以通过类的名称在类定义外部访问静态成员
**/
class Human{
public $name;
protected $height; //只有自身和子类可以访问
public $weight;
private $isHungry=true; //不能被子类访问
public static $sValue = "Static value in Human class. <br/>";
public function eat($food){
echo $this->name.".'s eating ".$food."\n";
}
public function info(){
echo $this->name.";".$this->height.";".$this->isHungry."<br/>";
}
}
class Animal{
}
class NbaPlayer extends Human{
//定义属性
public $team="Bull";
public $playerNumber="23";
private $age="40"; //private的类成员只能在类的内部被访问
//静态属性定义时在访问控制关键字后面添加static关键字即可
public static $president = "David Stern";
//静态方法定义
public static function changePresident($newPrsdt){
//在类定义中使用静态成员的时候,用self或者static关键字后面跟着::操作符即可。注意,在访问静态成员的时候,::后面需要跟$符号($this->president不需要加$符号)
self::$president = $newPrsdt; //等效于static::$president=$newPrsdt;
//使用parent关键字就能够访问父类的静态成员
echo parent::$sValue;
//$this->age; //这句话会返回这句错误:Fatal error: Using $this when not in object context in /var/www/html/oo.php on line 41
}
function __construct($name,$height,$weight,$team,$playerNumber){
echo "In NbaPlayer Constructor\n";
$this->name=$name; //父类中的属性,可以通过$this->来访问
$this->height=$height; //在父类是protected,子类里面可以访问
$this->weight=$weight;
$this->team=$team;
$this->playerNumber=$playerNumber;
}
function __destruct(){
echo "Destroying ".$this->name."<br/>";
}
//定义方法
public function run(){
echo "Running\n";
}
public function jump(){
echo "Jumping\n";
}
public function dribble(){
echo "Dribbling\n";
}
public function shoot(){
echo "Shooting\n";
}
public function dunk(){
echo "Dunking";
}
public function pass(){
echo "Passing";
}
public function getAge(){
echo $this->name."'s age is ".($this->age-2)."<br/>"; //如果不加括号会只打印-2,output是38 (真实年龄是40,38是假年龄)
}
}
//在类定义外部访问静态属性,我们可以用类名加::操作符的方法来访问类的静态成员以及方法
echo NbaPlayer::$president."before change <br/>";
NbaPlayer::changePresident("Adam Silver");
echo NbaPlayer::$president."after change <br/>";
echo Human::$sValue;
?>
output:
David Stern before change
Static value in Human class.
Adam Silver after change
Static value in Human class.
面向对象--Final成员
问题
• 对于吃饭这个功能,不希望子类修改它
• 对于NBA球员这个类,不希望再创建它的子类
使用类的Final成员特性就可以达到这样的效果
• final关键字(PHP 5)
示例一:
<?php
//子类中编写跟父类方法名称完全一致的方法可以完成对父类方法的重写(overwrite)
//对于不想被任何类继承的类可以在class之前添加final关键字
//对于不想被子类重写(修改)的方法,可以在方法定义的前面添加final关键字
class BaseClass{
public function test(){
echo "BaseClass::test called";
}
//添加final关键字能够让这个方法不能够在子类中重写
final public function test1(){
echo "BaseClass::test1 called";
}
}
class ChildClass extends BaseClass{
public function test($tmp=null){
echo "ChildClass::test callled".$tmp;
}
public function test1(){
echo "ChildClass::test1 callled";
}
}
$obj=new ChildClass();
$obj->test();
?>
output:
ChildClass::test callled
示例二:
<?php
//子类中编写跟父类方法名称完全一致的方法可以完成对父类方法的重写(overwrite)
//对于不想被任何类继承的类可以在class之前添加final关键字
//对于不想被子类重写(修改)的方法,可以在方法定义的前面添加final关键字
class BaseClass{ //如果这里的class前面加上final,output将返回这个错误,子类将不能继承父类:Fatal error: Class ChildClass may not inherit from final class (BaseClass) in /var/www/html/oo.php on line 21
public function test(){
echo "BaseClass::test called";
}
//添加final关键字能够让这个方法不能够在子类中重写
final public function test1(){
echo "BaseClass::test1 called";
}
}
class ChildClass extends BaseClass{
public function test($tmp=null){
echo "ChildClass::test callled".$tmp;
}
/* 如果加上了这个子类的方法,output将返回这个错误,显示不能重写父类的test1方法:Fatal error: Cannot override final method BaseClass::test1() in /var/www/html/oo.php on line 25
public function test1(){
echo "ChildClass::test1 callled";
}
*/
}
$obj=new ChildClass();
$obj->test1(); //虽然父类方法被final定义了不能被重写,但是可以调用
?>
output:
BaseClass::test1 called
面向对象 - 数据访问
<?php
/**
* 1. parent关键字可以用于调用父类中被子类重写了的方法
* 2. self关键字可以用于访问类自身的成员方法,也可以用于访问自身的静态成员和类常量;不能用于访问类自身的属性;使用常量的时候不需要在常量名称前面添加$符号
* 3. static关键字用于访问类自身定义的静态成员,访问静态属性时需要在属性前面添加$符号
**/
class BaseClass{
public function test(){
echo "BaseClass::test called";
}
public function test1(){
echo "BaseClass::test1 called";
}
}
class ChildClass extends BaseClass{
const CONST_VALUE = 'A constant value';
private static $sValue = 'static value';
public function test($tmp=null){
echo "ChildClass::test callled".$tmp;
parent::test(); //用parent关键字可以访问父类中被子类重写的方法
self::called(); //通过self关键字来访问自身的方法
echo self::CONST_VALUE."<br/>";
echo static::$sValue."<br/>";
}
public function called(){
echo "ChildClass::called() called";
}
}
$obj=new ChildClass();
$obj->test();
?>
output:
ChildClass::test callled
BaseClass::test called
ChildClass::called() called
A constant value
static value
面向对象--接口
问题
- 人会吃饭,动物也会吃饭
- 有些植物也可以吃东西(比如猪笼草)
- 吃这个动作(方法)动物和植物的实现方式是不一样的
吃这个行为没有统一的实现方式
- 动物张嘴咀嚼
- 植物直接包裹融化
接口就是把不同类的共同行为进行了定义,然后在不同的类里面实现不同的功能
<?php
//Interface关键字用于定义接口
//定义接口
interface ICanEat{
//接口里所有的方法都不需要有方法的实现
public function eat($food);
}
//implements关键字用于表现类实现某个接口
class Human implements ICanEat{
//实现了某个接口之后,必须提供接口中定义的方法的具体实现。
public function eat($food){
echo "Human eating ".$food."\n";
}
}
class Animal implements ICanEat{
//实现了某个接口之后,必须提供接口中定义的方法的具体实现。
public function eat($food){
echo "Human eating ".$food."\n";
}
}
//创建一个新的Human对象
$obj=new Human();
$obj->eat('Apple');
$monkey=new Animal();
$monkey->eat('Banana');
//不能实例化接口
//$eatObj=new ICanEat();
//可以用instanceof关键字来判断某个对象是否实现了某个接口
var_dump($obj instanceof ICanEat);
function checkEat($obj){
if($obj instanceof ICanEat){
$obj->eat('food');
}else{
echo "The obj can't eat. \n";
}
}
//相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态
checkEat($obj);
checkEat($monkey);
//可以用extends让接口继承接口
interface ICanPee extends ICanEat{
public function pee();
}
//当类实现子接口时,父接口定义的方法也需要在这个类里面具体实现
class Human1 implements ICanPee{
public function pee(){}
public function eat($food){}
}
?>
Output:
Human eating Apple
Human eating Banana
bool(true)
Human eating food
Human eating food
总结
某个类实现(implements)了某个接口和继承(extends)了某个类的区别
• 实现接口跟继承类很类似,但是接口不能直接创建自己的对象
∘ 如果创建了"会吃东西"这个接口的对象,那么具体怎么吃根本不知道
• 继承的父类必须有该方法的具体实现,子类可以重写父类的方法,也可以不重写
• 接口里面的方法是不需要具体实现的,只要定义了方法的名称和参数就可以了,具体的实现必须在实现类中定义
• 一句话概括:类的方法必须有实现,接口的方法必须为空
面向对象--多态
因为接口的方法实现可以有很多,所以对于接口里面定义的方法的具体实现是多种多样的,这种特性我们成为多态
-比如接口A有两个实现B和C,B和C对A里面定义的方法的实现可以是不同的,这种现象就是多态。
案例
//相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态
checkEat($obj);
checkEat($monkey);
面向对象--抽象类
接口里面的方法都是没有实现的,而类里面的方法都是有实现的
有没有一种形态,允许类里面一部分方法不实现呢?介于接口和类的定义之间
- 当接口中的某些方法对于所有的实现类都是一样的实现方法,只有部分方法需要用到多态的特性
实例
- 人和动物吃东西是不同的,但是呼吸是相同的,不需要为人和动物分别实现呼吸的功能
<?php
//abstract关键字用于定义抽象类,在抽象方法前面添加abstract关键字可以标明这个方法是抽象方法,不需要具体的实现
abstract class ACanEat{
abstract public function eat($food); //以后需要具体实现的在前加上abstract
//抽象类中可以包含普通的方法,有方法的具体实现
public function breath(){ //需要实现的直接实现
echo "Breath use the air. \n";
}
}
//继承抽象类的关键字是extends
class Human extends ACanEat{
//继承抽象类的子类需要实现抽象类中定义的抽象方法
public function eat($food){
echo "Human eating ". $food . "\n";
}
}
class Animal extends ACanEat{
public function eat($food){
echo "Animal eating ". $food . "\n";
}
}
$man = new Human();
$man->eat('Apple');
$man->breath(); //和Animal类共用了抽象类中的breath方法
$monkey = new Animal();
$monkey->eat('Banana');
$monkey->breath();
?>
Output:
Human can eat: Apple
Breath the air
Animal can eat: Banana
Breath the air