php-面向对象
$this是一个“伪对象”,代表当前所属类的当前对象。
一个系统函数:get_class(对象) 作用:获得某个对象的“所属类名”——结果只是一个类名字符串。
$class_name = get_class($p1); //结果可能是:”Person”
静态属性就是:只隶属于类本身——也可以看做是所有对象的“共有数据”。
类::$静态属性名;
类名::静态方法名();
注意1:$this在静态方法中不能使用。
静态方法中不应调用非静态方法。
self 含义:代表当前类
使用:通常只能在某个类的某个方法内部代表该类的名称。
构造方法
构造方式是类中的一个“特殊”方法,其作用是在实例化一个对象的同时,给该对象的属性赋值,使之一创建完成,就具有了其本身的特有数据(属性值)。
1,该方法名字是固定的,为:__construct();
2,该方法必须是普通方法(不能是静态方法)
3,通常该方法应该是public
4,通常该方法中使用$this这个关键字来对属性进行赋值
5,当new 类名()的时候,其实是在调用该构造方法
6,如果一个类中定义了构造方法,则实例化该类时就会调用该方法,且实例化时的参数需要跟构造方法的参数匹配
析构方法
构造方法是“创建”对象的时候会自动调用。
析构方法是“销毁”对象的时候会自动调用。
说明:
1,析构方法通常不太需要去定义。
2,析构方法不能调用。
3,析构方法不能有形参。
4,析构方法中可以用于清理一些在php代码结束后不能清理的数据,如生成的文件。
对象销毁的几个情形:
脚本程序运行结束,自动销毁;
明确地unset()一个对象变量,则被销毁;
改变对象变量的值,被销毁;
实际上,更本质来说,当一个对象(new 出来的对象)没有任何一个变量指向它的时候,该对象就会被自动销毁——自然,如果整个程序结束,也会销毁。
构造方法析构方法在继承中的表现
子类中没有定义构造方法时,会自动调用父类的构造方法。因此实例化子类时,需按照父类的构造方法的形式进行。
子类定义了自己的构造方法,则不会自动调用父类的构造方法,但可以手动调用:parent::__construct();
重写override
重写又叫覆盖,就是将从父类继承下来的属性或方法重新“定义”——就是从新写。
访问控制权限:
下级的访问控制权限应该不低于上级的访问控制权限:
上级:public 下级:只能public
上级:protected 下级: protected, public
上级:private 下级:private protected public——实际此情况无意义。
私有的不能覆盖,而是完全当作自己全新的。
构造方法的重写问题:构造方法不但可以像其他普通方法一样重写,而且,比普通方法更宽松:重写的时候参数可以不一致
最终类final class:
通常,一个类,没有特别声明的话,则“别人”就可以随意拿过来使用并对之进行“扩展”——继承。
但是:
如果某个类不希望对其进行扩展,则可以将其声明为“最终类”。
形式:
final class 类名{ 。。。。类定义。。。。}
最终方法final method
通常,一个方法,如果没有特别声明,则下级类就可以对其进行“覆盖”(重写)。
但是:
如果某个方法不希望被下级类覆盖,就可以对其生命为“最终方法”。
形式:
final function 方法名(){。。。。方法定义。。。。}
PHP中的重载技术
通常面向对象语言的重载技术
其基本语法是这样的:
在一个类中,有多个同名的方法,每个方法的参数不同而已。这种现象就称为“重载”。
参数不同可以是:数量个数不同,或类型不同,或顺序不同。
比如:
class A{
int function f1(int x){......}
int function f1(int x, int y){.....}
int function f1(string s int m){....}
}
但,在php中,一个类中,根本就不可以定义多个同名方法——这直接是语法错误。
实际上,php中的重载,是另一个“概念”,其指的是:
属性重载: 如果使用一个不存在的属性,就会去自动调用类中预先定义好的某个方法以处理数据;
方法重载: 如果使用一个不存在的方法,就会去自动调用类中预先定义好的某个方法以处理该行为
属性重载
属性有哪些使用情形?其实跟变量一样,只有4种使用情形:
取值:$v1 = 对象->属性;
赋值:对象->属性 = XX值;
判断是否存在:isset(对象->属性;)
销毁:unset(对象->属性;)
所谓属性重载,就是在面对上述4种情形的属性使用场景中,该对象如果来“应对”的问题。
如果某属性不存在,但在语法中使用如下情形,则会发生:
取值:$v1 = 对象->属性; ===>自动调用类中的__get()方法
赋值:对象->属性 = XX值; ===>自动调用类中的__set()方法
判断是否存在:isset(对象->属性;) ===>自动调用类中的__isset()方法
销毁:unset(对象->属性;) ===>自动调用类中的__unset()方法
前提都是:类中要预先定义好这些方法。
通常,没有的属性,去使用,显然是报错:
方法重载
当使用一个对象调用一个不存在的普通方法的时候,会自动去调用预先定义好的"__call"方法。
其中,该方法必须带2个参数,见下图:
当使用一个对象(类)调用一个不存在的静态方法的时候,会自动去调用预先定义好的"__callStatic"方法。
其中,该方法必须带2个参数。其实跟前面一样!
上面所学的几个方法都被称为“魔术方法”:
__get(), __set(), __isset(), __unset(), __call(), __callstatic();
类的自动加载
类的自动加载是指,在外面的页面中,并不需要去“引入”(包含)类文件,但是程序会在需要一个类的时候就自动去“动态加载”该类。
什么叫做“需要一个类”?通常是这样的情况:
1,创建一个对象的时候(new)
2,直接使用一个类名(操作静态或静态方法)
做法非常简单:
做法1:使用__autoload魔术函数。
即,“当程序需要一个类”的时候,就会去调用该函数:该函数我们需要自己去定义并在其中写好加载类文件的通用语句:
做法2:使用spl_autoload_register函数
该函数的作用是:用它“注册”(声明)多个可以用来代替__autoload函数作用的函数,语法如下:
spl_autoload_regist(“函数名1”);
spl_autoload_regist(“函数名2”);
.........
自然,其后也得去定义这些函数,并且这些函数的作用跟__autoload一样,不过此时就可以应对“更多的情形”——比如类文件分布在不同的目录中。
对象的复制(克隆)clone
浅克隆:
只能克隆对象中的“非对象非资源”数据:
但,如果对象中的属性存储的是“对象”类型,则就可以看到克隆不完全的情形,如下:
可见,修改了o1中的b1数据,发现o2种的b1数据也跟着改变了——克隆不完全。
我们可以使用“深克隆”来解决:
php中,默认克隆是浅克隆
要想实现深克隆(一个对象的所有属性数据都彻底实现了“复制”),就需要对该对象类使用魔术方法:
__clone(),并在里面来实现深度克隆——人为去复制浅克隆复制不了数据。
则刚才的代码,改进如下:
对象遍历
对象也可以可以使用foreach语句进行便利,有两点注意:
1,只能便利属性。
2,只能便利“看得到”的属性——代码所在范围可访问。
在外面遍历:
可见,此时protected和private属性都没有遍历出来。
如果需要全部遍历,则改造为:
将数据转换为对象
转换基本语法:(目标类型)数据;
对象转换为对象:没有变化;
数组转换为对象:数组的键名当作属性名,值为对应值;
但通常,如果数数字下标,则其对应属性 并不方便操作(->)
所以通常就适合于纯字符下标的数组。
与类有关的魔术常量:
__CLASS__,:获取其所在的类的类名。
__METHOD__:获取其所在的方法的方法名。
class A{
function f1(){
echo __CLASS__; //输出“A”
echo __METHOD__; //输出“f1”
//注意:get_class()也可以得到类名,但其必须有个“对象”
}
}
__tostring()方法
当把一个对象当作一个“字符串”来看待(处理)的时候,会自动调用该魔术方法。
通过该方法,可以返回“合适”的字符串,也可以认为就是对象转换为字符串的结果。
如果没有改方法,会出错。
对象不能直接当字符串使用:
__invoke()方法
对象当作一个“方法”(函数)的时候,会自动调用该魔术方法。
比如:
$v1 = $obj(1,2); //$obj其实是一个对象,这里就相当于将对象当函数用
一些有关类和对象的系统函数和运算符
class_exists(), :判断某个类是否存在(定义过)
interface_exists(), :判断接口是否存在
get_class():获取某个对象的“所属类名”
get_parent_class(), :获取某个对象的“所属父类的类名”
get_class_methods(), :获取一个类的所有方法,返回一个索引数组,就是这些方法的名字。
get_class_vars(), :获取一个类的所有属性,返回一个数组,下标为属性名,值为属性值。
get_declared_classes():获得所有声明过的类(含系统中的类)
is_object():判断是否对象
get_object_vars():获得对象的所有属性,返回一个数组,下标为属性名,值为属性值
运算符:
new:
instanceof: 判断一个对象是否是某个类的“实例”