一、常见的关键字和魔术方法
1、final关键字的应用
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
final关键字只能用来定义类和定义方法。
使用final关键字标记的类不能被继承final class Person{ ....... } class Student extends Person{ ....... } 会出现错误提示。Fatal error :Class Student may not inherit from final class(Person)
使用final关键字标记的方法不能被子类覆盖class Person{ final function Say(){ ...... } } class Student extends Person{ function Say(){ ...... } }
会出现下面错误:
Fatal Error:Cannot Override final method Person::say()
2、static关键字的使用
使用static关键字可以将类中的成员标识为静态的,既可 以用来标识成员属性,也可以用来标识成员方法。普通成员作为对象属性存在,以Person类为例,如果在Person中有一个"$conuntry = ‘china‘"的成员属性,任何一个Person类的对象都会拥有自己的一份$country属性,对象之间不会干扰。而static成员是作为整个类的属性存在,如果将$country属性使用static关键字标识,则不管通过Person类创建多少个对象(甚至可以是没有对象),这个static成员总是唯一存在的,在多个对象之间共享的。因为使用static标识 的成员属性是属于类的,所以与对象实例和其他的类无关。类的静态属性非常类似于函数的全局变量。类中的静态成员是不需要对象而使用类名来直接访问的,格式如下所示:
类名::静态成员属性名;
类名::静态成员方法名();
在类中声明的成员方法中,也可以使用关键字"self"来访问其他静态成员。因为静态成员是属于类的,而不属于任何对象,所以你不能用$this来引用它,而在PHP中给我们提供 的self关键字,就是在类的成员用来代表本类的关键字。格式如下 所示;
self::静态成员属性名; //在类的成员方法中使用这种方式访问本类中的静态成员属性
self::静态成员方法名(); //在类的成员方法中使用这种方式访问本类中的静态成员方法
如果在类的外部访问类中的静态成员,可以使用对象引用和使用类名访问,但通常选择用类名来访问。
如果在类内部的成员方法中访问其他的静态成员,通常使用self的形式去访问,最好不要直接使用类名称。
在下面的例子中声明一个Myclass类,为了让类中的count属性可以在每个对象中共享,将其声明为static成员,用来统计通过Myclass类一共创建了多少对象。代码如下所示:
<?php class Myclass{ static $count; function __contruct(){ self::$count++;//在类的内部通常使用self形式访问 } static function getcount(){ } static function gecount() return self::$count;//在类的内部,通常使用self的形式去访问 } } Myclass::$count=0; $myc1 = new Myclass(); $myc2 = new Myclass(); $myc3 = new Myclass(); echo Myclass::getCount();//在类的外部,通常选择用类名来访问。 echo $myc3->getCount();
上例的Myclass类中,在构造方法内部和成员方法getCount()的内部,都使用self访问本类中使用static标识为静态的属性count,并在类的外部使用类名访问类中的静态属性。可以看到同一个类中的静态成员在每个对象中共享,每创建一个对象静态属性count就自增1.用来统计实例化对象的次数。
另外在使用静态方法时需要注意,在静态方法中只能访问静态成员。因为非静态的成员必须通过对象的引用才能访问,通常是使用$this完成的。而静态的方法在对象不存在的情况下也可以直接使用类名来访问,没有对象就没$this引用,没有了$this引用就不能访问类中的非静态成员,但是可以使用类名或self在非静态方法中访问静态成员。
3、单态设计模式
3.1.单态设计模式含义:
单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。
3.2.单台模式的三个关键点:
① 需要一个保存类的唯一实例的静态成员变量;
②构造函数和克隆函数必须声明为私有的,防止外部程序new类从而失去单例模式的意义;
③必须提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一实例的一个引用 。
<?php class DB { private static $obj = null; //声明一个私有的,静态的成员属性$obj private function__construct() { //私有构造方法,只能在类的内部实例化对象 //在该方法中完成数据局的连接等操作 echo "连接数据库成功<br>"; } public static function getInstance() { // 通过此静态方法才能获取本类的对象,该方法为静态方法,用类名调用 if(is_null(self::$obj)) //如果本类中的$obj为空,说明还没有被实例化过 self::$obj = new self(); //实例化本类对象 return self::$obj; //返回本类的对象 } public function query($sql) { //执行SQL语句完成对数据库的操作 echo $sql; } } $db = DB::getInstance();//类名调用 //只能使用静态方法getInstance()去获取DB类的对象,获取后执行下一句完成对数据库的操作 $db -> query("select *from user"); //访问对象中的成员
4、instanceof关键字
PHP5的另一个新成员是instdnceof关键字。使用这个关键字可以确定一个对象是类的实例、类的子类,还是实现了某个特定接口,并进行相应的操作。在某些情况下,我们希望确定某个类是否特定的类型,或者是否实现了特定的接口。instanceof操作符非常适合完成这个任务。instanceof操作符检查三件事情:实例是否某个特定的类型,实例是否从某个特定的类型继承,实例或者他的任何祖先类是否实现了特定的接口。例如,假设希望了解名为manager的对象是否为类Employee的实例:
$manager = new Employee(); … if ($manager instanceof Employee) echo "Yes";
有两点值得注意。首先,类名没有任何定界符(引号)。使用定界符将导致语法错误。其次,如果比较失败,脚本将退出执行。instanceof关键字在同时处理多个对象时特别有用。例如,你可能要重复地调用某个函数,但希望根据对象类型调整函数的行为。可以使用case语句和instanceof关键字来实现这个目标。
class test{} class test{} class testChilern Extends test{} $a = new test(); $m = new test(); $i = ($m instanceof test); if($i) echo ‘$m是类test的实例!<br />‘; // get this value switch ($a instanceof test){ case true : echo ‘YES<br />‘; break; case false : echo ‘No<br />‘; //get this value break; } $d=new testChilern(); if($d instanceof test)echo ‘$d是类test的子类!<br />‘; // get this value
5、克隆对象
<?php class Person { //声明类Person,并在其中声明了三个成员属性,一个构造方法以及一个成员方法 private $name; //第一个私有成员属性$name用于存储人的名子 private $sex; //第二个私有成员属性$sex用于存储人的性别 private $age; //第三个私有成员属性$age用于存储人的age function __construct($name="", $sex="", $age=1) { //构造方法在对象诞生时为成员属性赋初值 $this->name=$name; $this->sex=$sex; $this->age=$age; } function __clone() { //声明此方法则在对象克隆时自动调用,用来为新对象重新赋值 $this->name="我是".$that->name."的副本"; //为副本对象中的name属性重新赋值 $this->age=10; //为副本对象中的age属性重新赋值 } function say() { //一个成员方法用于打印出自己对象中全部的成员属性值 echo "我的名子叫:".$this->name." 性别:".$this->sex." 我的年龄是:".$this->age."<br>"; } } $p1=new Person("张三", "男", 20); //创建一个对象并通过构造方法为对象中所有成员属性赋初值 $p2=clone $p1; //使用clone克隆(复制)对象,并自动调用类中的__clone()方法 $p1->say(); //调用原对象中的说话方法,打印原对象中的全部属性值 $p2->say(); //调用副本对象中的说话方法,打印出克隆对象的全部属性值 ?>
6、自动加载类
在面向对象程序设计时,通常为每个类单独建立一个PHP文件,使用时,可以用include包含一个类所在源文件,但是如果要使用太多的类,就比较麻烦。PHP提供了类的自动加载功能,__autoload全局函数,参数为类的名称。
此函数所调用的类源文件必须与autoload函数在同一个目录下:
<?php function __autoload($className) { //在方件的上方声明一个自动加载类的方法 // include("class_" . ucfirst($className) . ".php"); //在方法中使用include包含类所在的文件 include(strtolower($classname).".xxx.php") } $obj = new User(); //User类不存在则自动调用__autoload()函数,将类名“User”做为参数传入 $obj2 = new Shop(); //Shop类不存在则自动调用__autoload()函数,将类名“Shop”做为参数传入 ?>
7、对象的串行化
对象通过写出描述自己状态的数值来记录自己,称为对象的串行化。
在网络中传输对象的时候以及向数据库中保存文件的时候需要把对象串行化。
全部串行化:
1.serialize(对象名) 将指定的类对象串行化 $str=serialize($per) //将per对象串行化,结果返回给$str
2.unserialize(串行化后的返回值) 返回结果是对象 $per=unserialize($str);
局部串行化:
3.__sleep() 串行化某对象的部分属性。
4.__wakeup()反串行化时,初始化(其实是修改)对象内容
前两个的使用方法我们大概已经介绍过,接下来我们简单介绍一下__sleep()和__wakeup()使用方法
1.如果我们只想串行化一个对象中的部分属性我们可以使用 __sleep()函数
在类定义中添加
function__sleep()//只序列化类中的name和age成员 { $arr=new array(‘name‘,‘age‘); //name和age将被串行化,其他实属性将被忽略,反串行化后其他属性也将不存在 name和age必须是类中的属性 可以根据自己的实际需要增加 Return arr; }
2.假如我们在类串行化的时候,per对象的name属性值为“姜彤”在反序列化的时候我想改成"张三"怎么办
function __wakeup() { This->name="张三"; }