PHP面向对象(三)
前言
下面所讲的知识点都是个人从书中和各种教学视频里总结出来的一些小知识,可能总结的不是很到位,如果有总结的不对的地方,还希望各位简友指点...希望这篇文章能够对初学者有所帮助
本篇文章的学习目标
- 什么是接口?
- 类的自动加载
- 对象克隆和对象遍历
- 单例设计模式
接口技术
1:接口的基本概念?
- PHP类是单继承,也就是不支持多继承。
- 当一个类需要多个类的功能室,单继承就不能为力了,为此PHP引入了类的接口技术。
- 多人合作开发项目时,需要规范各个功能的名称,就需要用到接口技术。
- 接口就是一个标准,一个规范。类的功能实现,按照标准接口实现即可;
- 接口就是特殊的抽象类。可以理解为类的领导者,或者类中方法的目录大纲。
2:接口定义和实现要点
- interface 关键字定义接口;
- implements 关键字用来实现接口;
- 类可以继承类,接口可以使继承接口,但是类只能实现(implements)接口。
- 接口的方法权限必须是public;
- 接口中方法默认是抽象的,所有不需要再方法名前加abstract;
- 接口中方法可以使成员方法,也可以是静态方法;
- 接口中也可以定义常量,但常量不能重写
- 类可以实现(implements)多个接口(相当于把多个功能集于一身,如手机实现了打电话、听歌、放视频等功能);
举个例子:
//定义Inter1接口
interface Inter1{
//定义类常量
const TITLE = '<h2>接口的定义和实现演示</h2>';
//定义抽象的成员方法,不写方法体
public function showInfo();
}
//定义inter2 接口
interface Inter2 接口
interface Inter2{
//定义抽象的静态方法,不写方法体
public static function readMe();
}
//创建学生类,并同时实现两个接口
class student implements Inter,Inter2{
//重写showInfo()抽象方法
public function showInfo()
{
echo __METHOD__."<br>";
}
//重写静态的readMe()抽象方法
public static function readMe()
{
echo __METHOD__;
}
}
//定义最终的另一个学生类,并继承上一个学生类
final class fun_student extends student{}
//创建新的学生类对象
$obj = new fun_student();
$obj->showInfo();
fun_student::readMe();
类的自动加载
1:为什么需要类的自动加载?
很多初学者写面向对象的应用程序时,对每个类的定义,都建立一个独立的 PHP 源文件,方便类文件的统一管理,这无可厚非。但一个很大的烦恼是,不得不在每个脚本开头,写一个长长的包含文件列表(每个类一个文件)。这样一来,就增加了很多负担、占用了很多的内存,对于后期维护也不方便。
解决办法:按需要加载类文件,而不是把所有类全部包含进来.
2:类的常规加载:__autoload()
- 类的自动加载应用场景
在 PHP 5 中,定义一个 __autoload() 系统函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
提示:由于__autoload()不太灵活,在以后的版本中它可能被弃用。
- __autoload()函数详解
当试图使用未定义的类时自动调用,使用一个类的几种情况:
- 使用new关键字创建不存在类的对象时,__autoload()自动调用;例如:$obj = new Student()
- 当使用静态化方式访问一个不存在的类时,__autoload()自动调用,例如:Student::show();
- 当继承一个不存在的类时,__autoload()自动调用,例如:class Stu extends Parent{}
- 当实现一个不存在的接口时,__autoload()自动调用,例如:class Stu implements Inter
类文件的命名规范
- 一个类要单独定义成一个独立的类文件
- 类文件扩展名,要以"xxx.class.php"结尾,是一种规范,不是必须的;
- 类文件主名,要与类名一致;
- 例如:Db.class.php --- UserController.class.php
3:类的自定义加载:spl_autoload_register()
- 为什么要使用spl_autoload_register()加载类文件?
- 如果加载的类文件,位于不同的目录中,命名方式也不尽相同,__autoload()就显得不灵活了。
- spl_autoload_register()提供了一种更加灵活的方式来实现类的自动加载。
- 注意:在PHP7中,__autoload()已经被屏弃了。
语法格式
//语法格式
spl_autoload_register(func);
参数:func 参数可以使一个字符串的函数名
func参数可以使一个匿名函数
func函数代码功能,实现类文件的自动加载过程
说明:spl_autoload_register()可以多次调用,每次调用注册一种类文件的装载规则;
-
使用普通函数作为参数
//类的自定义加载 spl_autoload_register("func1"); spl_autoload_register("func2"); function fun1($className){ //构建类文件的真实路径 $filename = "./libs/$className.class.php"; //如果类文件存在,则包含 if(file_exists($filename))require_once($filename); } function func2($className){ //构建类文件的真实路径 $filename = "./public/$className.class.php"; //如果类文件存在,则包含 if(file_exists($filename))require_once($filename); } //创建教师类对象 $obj1 = new Teacher(); $obj1->showInfo(); //创建学生对象 $obj2 = new student(); $obj2->showInfo();
-
使用匿名函数作为参数
//类的自定义加载 spl_autoload_register(function($classname){ //构建不同类文件的真实路径的数组 $arr = array( "./libs/$className.class.php", "./public/$className.class.php" ); //循环判断数组中哪个类文件路径有效 foreach($arr as $filename) { //如果类文件存在,则包含 if(file_exists($filename)){ require_once($filename); } } }); //创建教师类对象 $obj1 = new teacher(); $obj1->showInfo(); //创建学生类对象 $obj2 = new student(); $obj2->showInfo();
对象克隆
1:什么是对象克隆
- 如果已存在了一个对象,而还想再创建一个新对象,并且,两个对象的属性值不一样,或者属性比原来多 ,怎么实现呢? $obj2 = $obj1 无法实现!
- $obj2 = $obj1,这不是复制对象,而是将$obj1和$obj2指向了同一个对象地址。
- 创建新对象有两种方式:a. 使用new关键字; b. 使用 clone 关键字
语法格式
//定义一个学生类
class student{
public $name = "小明";
public $age = 14;
}
//创建学生类的对象
$obj1 = new student;
//克隆对象
$obj2 = clone $obj1;
var_dump($obj1,$obj2);
2、魔术方法__clone()在克隆对象中的使用
-
当复制完成时,如果定义了 __clone()方法,则新创建的对象(复制生成的对象)中的 __clone()方法会被调用,可用于修改属性的值(如果有必要的话)。
//定义一个学生类 class student { public $name = "小明"; public $age = 14; //当克隆完成是,__clone()魔术方法自动调用 //在__clone()方法中对新对象进行一些操作. public function __clone() { $this->name = "小红"; $this->age = 15; $this->edu = "初中"; } } //创建学生类的对象 $obj1 = new student; $obj2 = clone $obj1;//克隆对象 var_dump($obj1,$obj2);
对象遍历
foreach 既可以遍历数组元素,也可以遍历对象属性;
//定义一个学生类
class student {
public $name = "小明";
public $age = 14;
private $edu = "初中";
protected $salary = 5000;
//在类内遍历对象属性
public function showAllAtter(){
//在类内遍历对象属性
foreach($this as $name=>$value){
echo "\$this->{name} = {$value}<br>";
}
}
}
//创建学生类对象
$obj = new student;
$obj->showAllAttrs();
//在类外输出的对象属性
echo "<h2>在类外输出的对象属性</h2>";
foreach($obj as $name=>$value){
echo "\$obj->{$name} = {$value}<br>";
}
从以上代码的输出结果来看,在类外只能输出public权限的属性....在类内可以输出所有权限的属性...
面向对象的设计模式
1:什么是对象设计模式?
设计模式(Design pattern)是一套被反复使用、多人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解,保证代码可靠性。
2:常用的设计模式有哪些?
- 单例设计模式:一个类只能创建一个实例对象,不管用什么办法都无法创建第2个对象;
- 工厂设计模式:生产不同类对象的工厂;
- 策略设计模式:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
- 观察者设计模式:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
提示:OOP中设计模式大约有几十种,可以上百度查。
3:单例模式的设计要求(三私一公)
- 一私:私有的静态的保存对象的属性;
- 一私:私有的构造方法,阻止类外new对象;
- 一私:私有的克隆方法,阻止类外clone对象;
- 一公:公共的静态的创建对象的方法;
4:单例设计模式演示
//单例设计模式的核心代码
class Db
{
//私有的静态的保存对象的属性
public static $obj = NULL;
//私有的构造方法,阻止类外New对象
public function __construct(){}
//私有的克隆方法,阻止类外Clone对象
public function __clone(){}
//公共的静态的创建对象的方法
public static function getInstance()
{
//判断当前对象是否存在
if(!self::$obj instanceof self)
{
//如果对象不存在,则创建并保存它
self::$obj = new self;
}
return self::$obj;
}
}
//创建数据库的对象
$db1 = Db::getInstance();
$db2 = Db::getInstance();
var_dump($db1,$db2);
//单例模式不管调用多少次,总是一个对象!
结束语
这篇文章只涵盖了我这几天所接触到的面向对象,并没有完全的总结,后续的学习中在持续更新吧,毕竟这个东西对我来说真的是挺难理解的。总结的可能不好,各位看官就将就着看吧。上面的例子可以复制到编辑器,然后自行查看效果。