对象的高级应用
1. PHP对象的高级应用
final关键字
final的含义是“最终的”“最后的”;被final修饰过的类和方法就是“最终版本”;
如果有一个方法的格式为:
final class class name{
//...
}
说明该类不再被继承,也不能有子类;
如果有一个方法的格式为:
final function method name()
说明该方法在子类中不能进行重写,也不能被覆盖;
例子: 为Employee类设置关键字final,并生成子类MyEmployee,
<?php
//创建final修饰的Employee类
final class Employee{
//构造方法
function __construct(){
echo "Employee类";
}
}
//创建Employee的子类
class MyEmployee extends Employee{
static function work(){
echo 'MyEmployee子类';
}
}
MyEmployee::work();
?>
2. 抽象类
抽象类是一种不能被实例化的类,只能作为其他的父类使用;
抽象类使用abstract关键字来声明,格式为:
abstract class AbstractName{
//....
}
抽象类和普通类相似,包括成员变量和成员方法;区别在于:抽象类至少要包含并重写某些特定的方法;
例子: 实现动物抽象类Animal,其中包含抽象方法eat();
<?php
//创建抽象类Animal
abstract class Animal{
//定义抽象方法
abstract function eat();
}
//定义Dog类,继承抽象类Animal
class Dog extends Animal{
//实现父类方法
function eat()
{
echo "狗喜欢吃骨头!";
}
}
//定义Cat类,继承抽象类Animal
class Cat extends Animal{
function eat()
{
echo "猫喜欢吃鱼!";
}
}
//实例化
$dog = new Dog();
$cat = new Cat();
//调用方法
$dog -> eat();
echo "<br>";
$cat ->eat();
?>
执行结果如下所示:
3. 接口的使用
继承特性简化了对象、类的创建,增加了代码的可重用性;
PHP只支持单继承,若想实现多继承,要使用到接口;PHP能实现多个接口;
接口通过interface关键字声明,并且接口中包含未实现的方法和一些成员变量,格式如下:
interface InterfaceName{
function interfaceName1();
function interfaceName2();
...
}
不用public
外的关键字来修饰接口中的类成员,对于方法,不写关键字也行;由接口自身的属性决定;
子类是通过implements关键字
来实现接口的,若要实现多个接口,每个接口之间要用逗号隔开;
接口中所有未实现的方法都需要在子类中全部实现,否则PHP户出现错误;
格式如下:
<?php
class itfClass implements InterfaceName1,InterfaceName2{
function InterfaceName1(){
...
}
function InterfaceName2(){
...
}
}
...
?>
例子: 声明两个接口Dogs和Animal,接着声明两个子类Dog和Huskie,其中Dog类继承了Dogs接口,Huskie类继承了Dogs和Animal接口;分别实现各自成员变量方法后,实例化两个对象$dog和$huskie
;再调用实现后的方法;
<?php
//声明接口Anim
interface Animal{
function eat();
}
//声明接口Dog
interface Dogs{
function play();
}
//定义了Dog,实现Dogs接口
class Dog implements Dogs{
function play()
{
echo "一只小狗与人类玩耍!";
}
}
//定义子类Huskie,实现Dogs接口与Animal接口
class Huskie implements Dogs,Animal{
function play()
{
echo "一只哈士奇狗不与人类玩耍!";
}
function eat()
{
echo "哈士奇什么都吃!";
}
}
//实例化
$dog = new Dog();
$huskic = new Huskie();
//调用Dog类的play()方法
$dog -> play();
echo "<br>";
//调用Huskie类的play()和eat()方法
$huskic ->play();
$huskic ->eat();
?>
执行结果如下所示:
抽象类和接口实现的功能非常相似;抽象类的优点在抽象类中实现公共方法,接口则能实现多重继承;
4. 克隆对象
1. 克隆对象
对象被当做普通的数据类型时使用;若想引用对象,要使用“&"来声明,不然PHP会按照默认的方式来按值传递对象;
例子: 实例化对象Employee类的对象传递给对象
e
m
p
1
,
emp1,
emp1,emp1的默认值为王某,再将对象
e
m
p
1
,
使
用
普
通
数
据
类
型
的
赋
值
方
式
赋
值
给
对
象
emp1,使用普通数据类型的赋值方式赋值给对象
emp1,使用普通数据类型的赋值方式赋值给对象emp2,改变
e
m
p
2
的
值
为
谢
某
,
再
输
出
对
象
emp2的值为谢某,再输出对象
emp2的值为谢某,再输出对象emp1的值;
php
<?php
//类Employee
class Employee{
//私有变量
private $name='王某';
//声明get/set方法
public function setName($name){
$this ->name = $name;
}
public function getName(){
return $this ->name;
}
}
//实例化
$emp1 = new Employee();
//使用普通数据类型的方式赋值给对象$emp2
$emp2 = $emp1;
//改变$emp2的值
echo "对象\$emp1的值为:".$emp1 -> getName();
?>
执行结果如下所示
2. __clone()方法
除了单纯的克隆外,有时候还要克隆对象拥有自己的属性和方法,可用__clone()方法
实现;
__clone()
的作用是:克隆对象的过程中,调用__clone()方法
,能使克隆出来的对象保持自己的一些方法和属性;
例子: 在类Employee中创建__clone()方法
,该方法实现的功能是将变量$name
的默认从王某改为谢某;使对象$emp1
克隆出对象$emp2
,输出$emp1
和$emp2
的$name
的值;
<?php
//类Employee
class Employee{
//私有变量
private $name='王某';
//声明get/set方法
public function setName($name){
$this -> name = $name;
}
public function getName(){
return $this -> name;
}
//声明__clone()方法
public function __clone(){
//将变量$name的值改为谢某
$this -> name ='谢某';
}
}
//实例化
$emp1 = new Employee();
//使用克隆的方法给对象$emp2赋值
$emp2 = clone $emp1;
//输出$emp1的值
echo "对象\$emp1的值为:".$emp1 -> getName();
echo "<br>";
//输出$emp2值
echo "对象\$emp2的值为:".$emp2 -> getName();
?>
执行结果如下所示:
5. 比较对象
在开发过程中,要判断两个对象之间的关系是克隆还是引用,用比较运算符 “==”
和 “===”
;两个等号是比较对象的内容,三个等号是比较对象的引用地址;
例子: 实例化对象$emp
,再分别创建克隆对象和引用,使用 “==”
和 “===”
判断它们之间的关系;
<?php
//创建Employee类
class Employee{
private $name;
function __construct($name){
$this -> name = $name;
}
}
//实例化对象
$emp = new Employee('王某');
//克隆对象$coneemp
$cloneemp = clone $emp;
//引用对象$emp1
$emp1 = $emp;
//==比较克隆对象与原对象
if($cloneemp==$emp){
echo "两个对象的内容相同<br>";
}
//====比较引用对象和原对象
if($emp1===$emp){
echo '两个对象的引用地址相同';
}
?>
执行结果如下所示:
6. 检测对象类型
instanceof
操作符能检测当前对象属于哪个类;
格式为:
ObjectName instanceofClassName
例子: 创建两个——基类Employee与子类Animal;实例化一个子类对象,判断该对象是否属于这个子类,再判断该对象是否属于这个基类;
<?php
//创建Employee
class Employee{}
//创建Animal类
class Animal extends Employee{
private $type;
}
//实例化对象
$animal = new Animal();
//判断是否属于Animal类
if($animal instanceof Animal){
echo "对象\$animal属于Animal类"."<br>";
}
//判断是否属于Employee类
if($animal instanceof Employee){
echo "对象\$animal属于Employee类"."<br>";
}
?>
执行结果如下所示:
7. 魔术方法(__)
PHP中保留了所有以“__"
开头的方法,只能使用PHP中已有的方法,不能自己创建;
1. __set()和__get()方法
两个魔术方法的作用分别为:
- 当程序尝试写入不存在或不可见的成员变量时,PHP会执行
__set()方法
;__set()方法
包含两个参数,分别表示变量名和变量值;参数不可省略
; - 当程序调用未定义的成员变量是,能通过
__get()方法
来读取变量值,__get()方法
有一个参数,表示要调用的变量名;
魔术方法,必须在类中进行定义才能使用,PHP不会执行未定义的魔术方法;
例子: 声明类Employee,在该类中创建一个私有变量KaTeX parse error: Expected group after '_' at position 14: type和两个魔术方法——_̲_set()和__get();…emp,先对已存在的私有变量进行赋值和调用,再对未声明的变量
$name`进行调用;
<?php
//类Employee
class Employee{
//私有变量
public $type='';
//__get()魔术方法
private function __get($name)
{
//判断是否被声明
if(isset($this -> $name)){
echo "\$name值为:".$this -> $name."<br>";
}else{
//未声明,则初始化
echo "变量\$name未定义,初始值为0<br>";
$this -> $name = 0;
}
}
}
$emp = new Employee();
$emp->type="Emp";
//调用变量
$emp->type;
$emp->name;
//创建Employee类
class Employee{
public function work(){
echo "work方法存在!<br>";
}
//call方法
public function __call($method,$parameter){
echo "方法不存在,执行__call()<br>";
echo "方法名:".$method."<br>";
echo "参数为:"; //参数是参数数组
var_dump($parameter);
}
}
//实例化对象
$emp = new Employee();
//调用存在的方法
$emp->work();
//调用不存在的方法
$emp->wor('王某',22,'南京');
?>
2. __call()方法
__call()方法
的作用是: 当程序试图调用不能存在或不可见的成员方法时,PHP会先调用方法来存储方法名及其参数;
__call()方法包含两个参数,方法名和方法参数;
方法参数是以数组的形式存在;
例子: 声明类Employee,该类包含两个方法——work()和play(),实例化对象$emp
需要调用两个方法:一个是类中存在的work()方法,另一个是不存在的wor()方法;
<?php
//定义类Employee
class Employee{
public function work(){
echo "work()方法存在!<br>";
}
//call方法
public function __call($method, $prameter)
{
echo "方法名不存在,执行__call()<br>";
echo "方法名:".$method."<br>";
echo "参数为:"; //参数是参数数组
var_dump($prameter);
}
}
//实例化对象
$emp = new Employee();
//调用存在的方法
$emp->work();
//调用不存在的方法
$emp-wor('王',33,'南京');
?>
执行结果如下所示:
3. __sleep()和__wakeup()方法
PHP使用serialize()函数
能实例化对象,即将对象中的变量全部保存下来,对象中的类则只保存类名;
在使用serialize()函数
时,若实例化对象包含__sleep()
方法,先执行__sleep()
方法;
该方法能清除对象并返回一个包含该对象中所有变量的数组;
使用__sleep()
方法的目的是关闭对象可能具有的类似数据库连接数据库后等善后操作;
unserialize()函数
能重新还原serialize()函数
序列化的对象,__wakeup()方法
则恢复在序列化中可能丢失的数据连接及相关工作;
例子: 声明类Employee,该类中有两个方法——__sleep()和__wakeup()
;实例化对象$emp
,使用serialize()函数
将对象序列化为一个子串$i
,最后使用serialize()函数
将子串$i还原成一个新对象;
<?php
//定义类Employee
class Employee{
//声明私有变量
private $name="王某";
//声明get方法
public function getName(){
return $this->name;
}
//声明魔法方法__sleep()
public function __sleep(){
echo "使用serialize()函数,将对象保存起来,能存放在本地或数据库中";
return array('name');
}
//声明魔术方法__wakeup()
public function __wakeup(){
echo "使用该数据时,用unserialize()函数对已经序列化的字符串进行操作,转换回对象";
}
}
//实例化对象
$div = new Employee();
//序列化对象
$i=serialize($div);
//输出字符串i
echo '序列化之后的字符串'.$i."<br>";
//重新转换会对象
$emp1 = unserialize($i);
//使用getName方法
echo '还原后的成员变量为:'.$emp1->getName();
?>
执行结果如下所示:
4. __toString()方法
魔术方法__toString()
的作用是:当使用echo或print
输出对象时,将对象转换为字符串;
例子: 输出类Employee的对象$emp,输出内容为__toString()方法返回的内容;
<?php
//定义类Employee
class Employee{
//声明私有变量
private $type="Emp";
//声明__toSring()方法
public function __toString(){
return $this->type;
}
}
//实例化对象
$emp = new Employee();
//输出对象
echo "对象\$emp的值为:".$emp;
?>
执行结果如下所示:
注意: 若没有__toString()方法
,直接输出对象将会发生致命错误(fatal error)
;
输出对象时应注意,echo或print
后面直接跟要输出的对象,中间不要加对于的字符,否则__toString()方法
不会被执行;
5. __autoload()方法
__autoload()方法
能自动实例化需要使用类;
例子: 创建类文件Employee.class.php;文件中包含类Employee,在创建index.php文件,在文件中创建__autoload()方法,手动实现查找功能,若查找成功,使用include_once()函数将文件动态引入;
Employee.class.php类文件
<?php
//定义类Employee
class Employee{
//声明私有变量
private $name;
//创建构造方法
public function __construct($name){
$this->name=$name;
}
//创建__toString()方法
public function __toString(){
return $this->name;
}
}
?>
index.php文件
<?php
//创建__autoload()方法
function __autoload($class_name){
//类文件地址
$class_path = $class_name.'Employee.class.php';
//判断类文件是否存在
if(file_exists($class_path)){
//动态引入类文件
include_once($class_path);
}else{
echo "类路径错误";
}
}
//实例化对象
$emp = new Employee("谢某");
//输出类的内容
echo $emp;
?>
执行结果不是预期的结果:
8. 面向对象的应用——中文字符串的截取类
例子: 编写MysubStr类,定义mysubstr()方法,实现对中文字符串的截取,避免在截取中文字符串时出现乱码问题;
<?php
class MsubStr{
//$str指定字符串,$start指定字符串的起始位置,$len指定长度
function csubstr($str,$start,$len){
//$strlen指定字符串的总长度
$strlen=$str+$len;
//for循环读取字符串
for($i=0;$i<$strlen;$i++){
//若字符串中首个字节的ASCII值大于0xa0,则表示汉字
if(ord(substr($str,$i,1))>0xa0){
//取两位字符,赋给变量$sstr,等于一个汉字
$tmpstr=substr($str,$i,2);
//变量加1
$i++;
}else{
//不是字符串,每次取出一位字符,赋给变量
$tmpstr=substr($str,$i,1);
}
}
//返回字符串
return $tmpstr;
}
}
//实例化类
$mc = new MsubStr();
?>
<table>
<tr>
<td>
<?php
$strs="PHP是一门通用,开源的脚本语言";
//判断字符串长度
if(strlen($str)>10){
//应用substr()函数截取字符串中的9个字符
echo substr($str,0,9)."...";
}else{
echo $str;
}
?>
</td>
</tr>
<tr>
<td>
<?php
$strs="语法吸收了C,java和Perl语言的特点";
//判断字符串长度
if(strlen($strs)>10){
//应用substr()函数截取字符串中的9个字符
echo substr($strs,0,9)."...";
}else{
echo $strs;
}
?>
</td>
</tr>
</table>
执行结果如下所示:
结束语
若这篇文章有帮到你,给个赞,收个藏,欢迎大家留言评论;
若文章有什么错误,欢迎大家指教。