面向对象知识(4)
类的自动加载
含义:
当某行代码需要一个类的时候,php的内部机制可以做到“自动加载该类文件”,以满足该行需要一个类的这种需求。
什么时候需要一个类?
1,new一个对象的时候;
2,使用一个类的静态方法的时候;
3,定义一个类(B)并以另一个类(A)作为父类的时候;

条件和要求
1, 当需要一个类的时候,就会自动调用某个函数(默认是__autoload),并传入所需要的类的名字
2, 一个类应该保存到一个独立的“类文件中”:即其中只有该类的定义,没有别的代码;
3,习惯上,类文件的命名要有一定的“规则”,通常是:类名.class.php
4,通常,我们需要将各种类,存储在一些特定的目录中,以方便确定其位置!
5,在该自动加载的函数中,“充分”使用传过来的类名,以构建一个合适的文件路径并载入;

自定义自动加载函数:
刚才,__autoload()函数,是系统内部的自动加载函数,我们只是定义其函数体。
但:
我们可以使用更多函数(自定义的),来实现更灵活的自动加载!
基本模式为:
spl_autoload_register(“函数1”); //声明“函数1”作为自动加载函数;
spl_autoload_register(“函数2”); //声明“函数2”也作为自动加载函数;
.........
然后,就去定义这些函数,跟定义__autoload()函数一样:
function 函数1( $class_name ){
//.......
}
function 函数2( $class_name ){
//.......
}
.............
这样,系统就会一次调用这些自动加载函数去加载所需要的类,直到加载成功!

对象的复制(克隆)
$obj1 = new A();
$obj1->p1 = 11;
$obj2 = $obj1; //值传递
//则,现在有几个对象?——1个对象!
当然:
$obj3 = & $obj1;
结果,还是一个对象!
对象的克隆语法,就是用于将一个对象“制作”双份的语法,类似之前普通数据的“值传递”;
语法:
$obj2 = clone $obj1; //这样,就有一个跟$obj1完全一样的新的对象。

对象的遍历
对象的遍历,跟数组的遍历,一样!
其实,只能遍历出对象的“实例属性数据”
foreach( $对象名 as $key => $value){
//这里就可以处理$key和$value
//但注意:
1, $key表示的是对象 的 “属性”,$value是其对应值;
2, 这里能够遍历出来的属性,只能是在该范围中的“可访问属性”(就是要考虑访问控制权限)
}

那,怎么能够将一个对象的所有属性都遍历出来呢?

PHP内置标准类
php语言内部,有“很多现成的类”,其中有一个,被称为“内置标准类”。
这个类“内部”可以认为什么都没有,类似这样:
class stdclass{ }

其作用,可以用于存储一些临时的简单的数据:
$obj1->pp1 = 1;
$obj1->port = ‘3306’;
也可以用于类型转换时用于存储数据,如下节所示
其他数据类型转换为对象类型
其他数据类型转换为对象类型,得到的结果是:内置标准类(stdclass)的一个对象!
语法形式为:
$obj1 = (object) 其他类型数据;
- 数组转换为对象:数组的键名当作属性名,值为对应值;
注意:数字下标的数据元素,转换为对象后的属性,无法通过对象语法获取,因此不推荐转换。


- null转换为对象:空对象;
$obj1 = (object)null;
- 其他标量数据转换为对象:属性名为固定的“scalar”,值为该变量的值:

类型约束
什么叫类型约束?
就是要求某个变量只能使用(接收,存储)某种指定的数据类型;
php属于“弱类型语言”,通常不支持类型约束;
相应的,强类型语言,类型约束却是其“基本特征”。
php中,只支持局部的部分类型约束
php中,只支持在函数(或方法)的形参上,设定类型的约束目标,形式如下:
function 方法名(【要求使用的类型】$p1 , 【要求使用的类型】$p2, ..... ){
//..........
}
说明:
1,定义一个函数(方法)时, 一个形参,可以使用类型约束,也可以不使用;
2,如果使用了类型约束,则对应的该实参数据,就必须是要求的那种类型。
3,能够使用的类型约束,其实非常少,只有以下几种可用:
数组: array,
对象:使用类的名称,表示,传递过来的实参,必须是该类的实例;
接口: 使用接口的名称,表示,传递过来的实参,必须是实现了该接口的类的实例

单例类的加强:禁止克隆
对于一个类的对象,如果使用“clone运算符”,就会克隆出一个跟当前对象完全一样的新对象出来,
并且:
此时还会自动调用该类中的魔术方法:_ _c l o n e ();只要其中有该方法;
则,要想实现单例类,就应该对这个单例类的对象“禁止克隆”,做法是:
私有化这个魔术方法:_ _c l o n e ();

以下为对单例模式的测试代码:

与类有关的其他魔术方法
序列化与反序列化技术
含义:
序列化:
就是将一个变量所代表的“内存”数据,转换为“字符串”形式并持久保存在硬盘上的一种做法。
反序列化:
就是将序列化之后保存在硬盘上的“字符串数据”,恢复为其原来的内存形式的变量数据的一种做法。
序列化的做法:
$v1 = 123; //这是一个变量,代表任意的内存数据
$s1 = serialize( $v1 ); //将任何类型的变量数据,转换为“字符串”
file_put_contents( ‘要保存的目标文本文件’, $s1); //将该字符串,保存到一个文件里(就是硬盘数据)
反序列化的做法:
$s1 = file_get_contents( ‘保存序列化数据的目标文本文件’); //从一个文件里读出其中的所有字符
$v1 = unserialize( $s1 ); //将该字符串数据,反序列化转换为变量(数据)
举例:
先进行基本数据的序列化:

再来对他们进行反序列化:

__sleep():用于对象的序列化:
1,对一个对象进行序列化,只能将其属性数据“保存起来”,而方法被忽略(方法不是数据)
2,对象的序列化的时候,会自动调用该对象所属类的这个魔术方法:__sleep()(前提是有该方法)。
且,此时,该方法必须返回一个数组,数组中是“计划”要进行序列化的属性名;
举例:
类文件内容如下:


__wakeup:用于对象的反序列化:
1,对一个对象进行反序列化,其实是恢复其原来保存起来的属性数据,而且,此时必然需要依赖该对象原本的所属类;
2,对象在反序列化的时候,会自动调用该对象所属类的这个魔术方法:__wakeup()
举例:

下面演示可选属性的序列化(通过__sleep):

然后,对其对象进行序列,并显示该对象的数据:

然后,在另一个页面中,对其进行反序列化:

__tostring()魔术方法——比较常用!
含义:
将一个对象“当做”一个字符串来使用的时候,会自动调用该方法,并且在该方法中,可以返回一定的字符串,以表明该对象转换为字符串之后的结果。
注意:
如果没有定义该方法,则对象无法当做字符串来使用!!!


__invoke()魔术方法:
将对象当作函数来使用的时候,会自动调用该方法。通常不推荐这么做。
class A{
function __invoke(){
echo “<br />我是一个对象呀,你别当我是一个函数来随便调用!”;
}
}
$obj1 = new A();
$obj1(); //此时就会调用类中的方法:__invoke()
其他零碎:
与类有关的魔术常量:
以前学过的魔术常量:
__FILE__
__DIR__
__LINE__
现在:
__CLASS__: 代表当前其所在的类的类名;
__METHOD__:代表其当前所在的方法名;

与类有关的系统函数:
class_exists(“类名”), 判断一个类是否存在(是否定义过)
interface_exists(“接口名”), 判断一个接口是否存在(是否定义过)
get_class( $obj ), 获得某个对象$obj 的所属类
get_parent_class($obj ), 获得某个对象$obj 的所属类的父类
get_class_methods(), 获得一个类的所有方法名,结果是一个数组,里面存储的是这些方法的名称
get_class_vars(), 获得一个类的所有属性名。结果是一个数组,里面存储的是这些属性的名称get_declared_classes() 获得“整个系统”所定义的所有类名;
与对象有关的系统函数:
is_object( $obj ): 判断某个变量是否是一个对象;
get_object_vars( $obj ):获得一个对象的所有属性;结果是一个数组,里面存储的是这些属性的名称
与类有关的运算符:
new,
instanceof: 判断一个“变量”(对象,数据),是否是某个类的“实例”;
示意如下:
class A {}
class B {}
class C extends A{}
$a1 = new A();
$b1 = new B();
$c1 = new C();
$v1 = $a1 instanceof A ; //结果是true
$v2 = $b1 instanceof A ; //结果是false
$v3 = $c1 instanceof C ; //结果是true
$v4 = $c1 instanceof A ; //结果是true
——推论:一个类的对象,必然也属于这个类的上级类的对象;
static关键字的新用法和总结:
static这个关键字,也可以像“self”一样,代表“当前类”,用于访问一个类的“静态属性或静态方法”;
但,static,在应用中,更灵活,因此更常见!
因为static,它代表的是“调用”当前方法的类,而不是“其代码所在的类”:
self它就比较死板,只代表这个单词本身所在位置的所在类。

static关键字的使用总结

面向对象编程思想的3个特征:
封装:
无非是一个大的指向思想,目的是为了将一个类设计得更为健壮!
其基本做法是:
尽可能地将一个类的成员私有化,只开放那些必不可少的对外的属性或方法,能private的就不要protected。能protected就不要public
继承:
是面向对象的基本思想和基本做法。
继承是代码重用的一种重要机制。
多态:
多态,就是“多种形态”,其实指的是,现实世界的“丰富多彩的表现形式”,比如:
人在吃饭;
猪在吃食;
鱼在进食;
小鸡啄米;
。。。。
他们都是“吃”这个行为!
在实际代码(应用)中,多态常常有两种表现形式:
1, 不同对象,使用相同的方法,会表现为不同的结果!
2, 同一个对象,使用相同的方法,也可能会表现为不同的结果——这其实是“方法重载现象”
浙公网安备 33010602011771号