一、对象的继承
1)什么是继承?
父类的内容可以拿到子类当中来使用
2)为什么要使用继承?
①更好地体现面向对象的可重用性
②避免代码的冗余
③可以在父类的基础上进行功能的扩展
④体现了面向对象的可扩展性
3)什么时候使用继承?
①在功能要进行扩展的时候进行继承
②在功能要进行修改的时候,子类的功能会覆盖父类的功能
4)PHP继承的特性:
①只支持单一继承,不支持多重继承
②一个子类只允许有一个父类
③一个父类可以有多个子类
5)PHP继承的关键字
①父类、基类、超类
②子类、扩展类、派生类
6)权限问题
①public:公有的成员在子类中可以被完全继承;子类中的成员如果与父类的公有成员的名称相同,则子类的成员功能将覆盖父类的成员功能;
②protected:受保护的成员在子类当中可以被完全继承;受保护的成员在子类中如果出现同名的成员,功能会被覆盖;
③private:父类中私有的成员在子类中不能直接拿来使用,不可被继承
④private < protected < public,子类中的同名的成员的权限一定要比父类的成员的权限宽松
7)方法的重载(覆盖)
parent::__construct();
parent::成员方法名();
class Person{
public $name;
public $sex;
public $age;
function __construct($name,$sex,$age){
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
public function say(){
echo "my name is ".$this->name.", my sex is ".$this->sex.", my age is ".$this->age;
}
}
class Student extends Person{
//继承成员属性$name、$sex、$age
public $school;
//构造方法同样被继承,并被覆盖重写
function __construct($name,$sex,$age,$school){
//将父类的构造方法的方法体继承下来
parent::__construct($name,$sex,$age);
$this->school=$school;
}
//将父类的say方法覆盖重写
public function say(){
//将父类的say方法的方法体继承下来
parent::say();
echo ", my shcool is ".$this->school;
}
}
$p=new Student("autumn","男",25,"haha");
$p->say();
二、常用的关键字
1)final
①final修饰的成员方法不允许在子类当中被重写,为了防止已经写好的功能被修改
②final只能修饰方法和类,不能修饰成员属性
③final修饰的类不能再被其他类继承
2)static
①static修饰的成员属性,在类的方法体中要使用“self::$属性名称”访问
②static修饰的成员属性保存在内存中的初始化静态段中,而在类中使用“$this->属性”所调用的成员属性是保存在堆当中的,所以static修饰的成员属性不能使用“$this->属性名称”来访问
③静态成员属性在类的外部可通过“类名::$成员属性名称”调用,不可使用对象来调用
④静态成员属性效率较高,因为不需要实例化对象即可调用
⑤同一个类的多个实例化对象共享一个静态成员属性
⑥静态的成员方法中不允许使用$this调用成员属性
⑦静态的成员方法在类的内部可以使用$this调用,也可以使用“self::方法名()”调用
⑧静态的成员方法在类的外部可以使用实例化对象调用,也可以使用“类名::方法名()”调用
⑨成员方法当中如果没有包含任何$this,该方法默认为静态成员方法
class Person{
public $username;
public static $name;
public function info(){
//普通成员属性的调用
//echo $this->username;
//静态成员属性的调用
echo self::$name;
}
public static function say(){
echo self::$name." say 'hello world!'";
}
public function test(){
//可以使用$this调用静态成员方法
//$this->say();
//也可使用“self::方法名()”调用
self::say();
}
}
//静态成员属性不可以使用对象来调用
$p1=new Person;
Person::$name="autumn";
$p2=new Person;
Person::$name="HaHa";
//多个实例化对象共享一个静态成员属性
$p1->info();
$p2->info();
echo "<hr>";
//可以用实例化对象调用静态成员方法
//$p1->say();
//也可以使用“类名::方法名()”调用(推荐使用)
Person::say();
3)单态设计模式
①什么是单态(单例)(单对象)设计模式?
让类只能实例化一个对象
②为什么要使用单态?
为了节省空间、提高效率
③什么时候使用单态设计模式?
数据库的连接池操作、文件资源的操作、GD资源的操作
④如何使用单态设计模式?
1.构造方法私有化,外部无法自动实例化对象
2.声明一个方法,在该方法中实例化对象
3.将产生的对象存入至一个共享的静态成员属性中
4.在外部想要再次实例化对象时,将该静态成员属性中的对象传给它,即仍为首次实例化的那个对象
class Person{
public static $obj; //用于保存首次实例化的对象
public $name;
//构造方法私有化,外部无法自动实例化对象
private function __construct($name){
$this->name=$name;
}
public static function getObj($name){
//判断该类的对象是否存在
if(is_null(self::$obj)){
self::$obj=new self($name);
}
//除首次实例化对象外,其余直接将首次实例化后存在静态成员属性中的对象传递过去
return self::$obj;
}
public function info(){
echo $this->name;
}
}
$p1=Person::getObj("autumn");
var_dump($p1);
echo "<hr>";
$p2=Person::getObj("haha");
var_dump($p2);
object(Person)#1 (1) { ["name"]=> string(6) "autumn" }
object(Person)#1 (1) { ["name"]=> string(6) "autumn" }
4)const
①常量名一般情况下用大写
②常量值为标量数据类型
③常量不要加“$”
④常量在类的内部访问用“self::常量名”
⑤常量在类的外部访问用“类名::常量名”
5)instanceof
①判断一个对象是否为一个类实例化的
②判断一个对象是否为继承父类的某个子类实例化的
class Person{
//声明一个常量成员属性
const DB_HOST="localhost";
public function info(){
//类的内部调用常量成员属性
echo self::DB_HOST;
}
}
class Student extends Person{
public $school="hehe";
public function say(){
parent::info();
echo ", my school is ".$this->school;
}
}
//类的外部调用常量成员属性
echo Person::DB_HOST;
echo "<hr>";
$p=new Person;
$s=new Student;
//instanceof用于检测当前实例对象是否属于某一个类
var_dump($p instanceof Student); //false
var_dump($s instanceof Student); //true
var_dump($s instanceof Person); //true
三、常用的魔术方法
1)克隆对象
①什么是克隆?
将一个对象完整的复制一份,这个对象与原对象一模一样
②克隆的目的
当对一个已经产生的对象进行一系列的修改、赋值等操作后,需要使用多个经操作后的对象时,使用克隆
③方法:__clone()
参数:无
触发时机:在使用clone对象的一瞬间自动调用
作用:将克隆出的对象进行微调,源对象不会被影响
2)__toString()
参数:无
触发时机:当在类的外部直接echo对象时,自动调用
作用:为了更好地操作对象
注意:本方法一定要有返回值
3)__call()
参数:两个(第一个是调用方法的名称,第二个是实际参数的数组)
触发时机:当调用一个不存在的成员方法时自动调用,且将方法的名称传递给第一个参数,将方法的调用参数传递给第二个参数
作用:避免程序报错,影响后续代码执行
class Person{
private $name="autumn";
private $sex="男";
private $age=25;
public function info(){
echo "姓名:".$this->name.",性别:".$this->sex.",年龄:".$this->age;
}
//在使用clone对象的瞬间自动调用__clone()方法
function __clone(){
$this->name=$this->name."_clone001";
}
//在类的外部echo对象时自动调用__toString()方法
function __toString(){
return "在类的外部直接echo对象会输出该段文字";
}
//当调用一个不存在的成员方法时自动调用__call()方法
function __call($funcName,$args){
echo "对不起,您要找的方法".$funcName."(".join(',',$args).")不存在!";
}
}
$p1=new Person;
//将对象$p1完整克隆一份
$p2=clone $p1;
var_dump($p1);
echo "<hr>";
var_dump($p2);
echo "<hr>";
echo $p1;
echo "<hr>";
$p1->noFunc('参数1','参数2','参数3');
4)__sleep()
参数:无
触发时机:当对一个对象序列化的时候自动调用
作用:让用户可以自定义要序列化的成员属性
注意:该方法一定要返回一个数组类型的值,数组元素的值即为成员属性的名称
5)__wakeup()
参数:无
触发时机:当对对象进行反序列化的时候自动调用
作用:反序列化对象时使对象中的成员发生改变
6)对象串行化(序列化)
将对象转化成以固定形式存储的字符串
①为什么使用对象的串行化?
为了能够让保存对象的介质能够识别对象的格式
②何时使用对象的串行化?
要将对象存入到数据库或是文件中
对象在网络中传输的时候可串行化
③方法:
serialize($obj):串行化(序列化)
unserialize($str):反串行化(反序列化),将对象反串行化时必须有原型类同时在
class Person{
private $name="autumn";
private $sex="男";
private $age=25;
public function info(){
echo "姓名:".$this->name.",性别:".$this->sex.",年龄:".$this->age;
}
public function __sleep(){
//指定要序列化的成员属性
return array('name','sex');
}
}
$p=new Person;
echo $str=serialize($p);
file_put_contents("./obj.txt",$str);
class Person{
private $name="autumn";
private $sex="男";
private $age=25;
public function info(){
echo "姓名:".$this->name.",性别:".$this->sex.",年龄:".$this->age;
}
public function __sleep(){
//指定要序列化的成员属性
return array('name','sex');
}
public function __wakeup(){
$this->name="admin";
$this->sex="保密";
}
public function say(){
echo "haha";
}
}
$str=file_get_contents("./obj.txt");
//将对象反序列化时,必须要原对象类同时在
$obj=unserialize($str);
$obj->info();
7)__autoload()
参数:一个(类的名称)
触发时机:当要实例化或继承使用未经include引入的类文件中的类的时候会自动调用该函数,且会将类名作为参数传入该函数,此时在该函数内部可实现类文件的加载
作用:用于加载类文件,无需像使用include加载类文件那样考虑加载的先后顺序
注意:这是一个函数并非是类的成员方法,不是用于类的内部的,而是在需要引用类文件时使用的
function __autoload($className){
if($className=='class1'){
include "../".$className.".class.php";
}elseif($className=='class2'){
include "../".$className.".class.php";
}elseif($className=='class3'){
include "./".$className.".class.php";
}
}
$p=new Person;
四、类型约束
1)类型约束可以使用数组约束和类名约束
2)数组约束:只需要在方法或函数的参数前加入array关键字即可
3)类名约束:只需要在方法或函数的参数前加入类名,表示调用时必须传递该类的对象或该类的子类的对象
class Person1{
function say(array $info){ //数组约束
echo "P1:".join(',',$info);
}
}
class Person2{
function say(array $info){ //数组约束
echo "P2:".join(',',$info);
}
}
class Person{
function test(Person1 $obj){ //类名约束
$obj->say(array('abc','ABC'));
}
}
$p=new Person;
$p->test(new Person1);