牛骨文教育服务平台(让学习变的简单)
博文笔记

php面向对象-一揽子方案

创建时间:2017-05-24 投稿人: 浏览次数:993

PHP-OOP1(万物皆对象!)-编程思想,类,属性,方法 一、编程思想:计算机解决实际问题的一种思维方式。 PHP是同时支持面向过程和面向对象两种编程思想的语言。 面向对象的核心思想是:不仅仅简单的将某些功能进行封装(封装成函数),更是对调用该功能的主体进行封装,实现某个      主体拥有多个功能,在使用的过程中,先得到对应的主体,再使用主体去实现相关的功能! 面向过程---自顶向下,逐步细化 面向对象---在编程的时候尽可能的模拟现实世界! 面向过程写代码,需要实现哪些功能以及如何去实现---1调用系统函数,2用户自定义函数,3流程控制(整体调度) 面向对象写代码,首先想到的是应该有什么样的主体去完成什么样的功能,再把该主体的属性和功能进行封装,再去实现该主体的功能! 面向对象与面向过程的区别 - 都可以实现代码重用和模块化编程,面向对象的模块化更深,数据更封闭,也更安全 - 面向对象的思维方式更加贴近于现实生活,也容易解决大型复杂的业务逻辑 - 从前期开发的角度看,面向对象比面向过程更复杂,但是,从维护和扩展功能的角度来看,面向对象要远比面向过程要简单! 二、1.面向对象三阶段OOA,OOD,OOP----------OOP:面向对象编程 对象是采用属性(property)来保存数据! 对象是采用方法(method)来管理数据! 对象是由类实例化而来的! 强调:无论在哪里,访问成员的属性和方法都要先找到其对象才可以! 二、2.1类的定义类就是具有相同或相似的特征特性的一组事物的一个通用的名称! 使用class关键字来定义! 2.2类的组成定义一个类,其实就是定义三种类成员:定义属性(变量),定义方法(函数),定义类常量(常量) 2.3类的实例化语法形式是:new 类名;      几点需要注意的地方: 1.属性和方法都需要进行声明才可以使用!(采用访问控制修饰限定符来声明public,proteced,private) 2.public可以用var代替,只是对低版本的一种兼容! 3.方法的前面可以省略掉访问控制修饰限定符,默认的就是public 4.在定义类的时候,属性值默认是NULL型,但是如果给属性上一个初始值必须是“直接值”,不能是表达式计算之后的值! //例:定义一个类     Class Student{      public $stu_name;      public $stu_money=30000;      public function payMoney(){           echo $this->stu_name,"刚交完",$this->stu_money,"学费,要好好学习";          } //this调用当前对象     }     $stu=new Student;//类的实例化     $stu->stu_name="鸣人";//访问对象的属性     $stu->payMoney();//调用对象的方法(方法必须有对象来调用才能执行,否则找不到方法) //执行结果: 鸣人刚交完30000学费,要好好学习 3.类成员的访问使用箭头  ->实现对象对对象成员的访问!      属性不能在方法内直接访问,需要找到其对象才能访问,典型的做法就是,在方法内使用this来代替当前对象的名称! 调用方法时,必须先通过对象找到所属类,然后再找到相应方法 打印实例时,为什么只能打印出属性而打印不出方法?      方法属于公共代码,存储在用户代码区,由类管理。而属性属于每个实例,由实例管理,3空间如下 类---------类空间---------类常量 类---------用户代码区-----方法 对象-------对象空间-------属性 4.面向对象的编程思想和过程 第一步:找到所有的实体 第二步:定义相关的类 第三步:实例化对象并初始化 第四步:执行相应的功能 5.构造方法 在实例化一个对象的时候,PHP会自动的调用一个名字叫作__construct()的方法,该方法由于专门负责对新对象进行初始化,称之为“构造方法”! 在实例化一个对象的时候,顺便在类名的后面增加一些用括号括起来的参数列表(可以理解为构造方法的实参)    创建初始化方法和构造方法    Class Student{      public $stu_name;      public $stu_money;      public function payMoney(){           echo $this->stu_name,"刚交完",$this->stu_money,"学费,要好好学习";          }      // public function init($m,$n){ //创建一个专门对对象的属性初始化的方法      //     $this->stu_name=$n;      //     $this->stu_money=$m;      // }      public function __construct($m,$n){ //构造方法          $this->stu_name=$n;          $this->stu_money=$m;      }    }     // $stu1=new Student;//类的实例化     // $stu1->init(30000,"鸣人");     // $stu1->payMoney();//调用对象的方法     echo "<br>";     $stu2=new Student(50000,"佐助");//类的实例化     $stu2->payMoney();//调用对象的方法 可兼容旧版本的构造方法书写方式:     public function __construct($n,$a,$m){         $this->Student($n,$a,$m);     }     public function Student($n,$a,$m) {         $this->stu_name = $n;         $this->stu_age = $a;         $this->stu_money = $m;     } 6.析构方法 主要的作用就是用于释放对象所占用的额外的资源!而不是对象本身! 析构方法的名字叫作__destruct(),注意,里面不能有任何的参数!在对象消失之前调用。因此还能使用$this! 对象消失的几种情况
    1. 明确的使用unset函数销毁一个变量
    2. 脚本运行结束之后,也会自动销毁
    3. 改变对象变量的值,也会自动销毁
常见的有一种删除对象的方法:$stu1 = NULL;      与构造方法是一对,构造方法是在一个对象“出生”的时候自动调用的,而析构方法是在一个对象“消失”的时候由系统自动调用的! PHP-OOP2(对象传值、克隆、静态,类常量,自动加载) 一、对象的传值 1.为什么对象之间,不管使用值传递还是引用传递,效果都是引用传递的效果? 本质:对象的变量名并不是直接引用对象的内存空间,而是引用对象的内部编号。而对象的值传递或者引用传递, 其实复制的都是这个编号,所以效果都是引用传递的效果。 2.对象间的复制,无法开辟一个新的对象空间,有时候,也称之为“浅复制”!例$stu2=$stu1; 3.那么,如何使用一个已有的对象,得到一个全新的对象呢(单独开辟新的内存空间)--需要使用对象的克隆! 二、对象的克隆(生成对象的两种方法之二)      1.所谓的克隆,不是通过类的实例化得到一个新对象,而是通过一个已有的对象得到一个新对象2.语法形式新对象 =  clone 已有对象------例:$stu2 = clone $stu1;      新旧对象之间,具有相同属性名和值,但是对象的内存空间不同(内部编号不同)      注意:克隆不是实例化,所以不需要执行构造方法!      3.使用instanceof运算符判断某个对象是否是由某个类实例化而来的! 形式为:对象变量 instanceof  类名---结果:返回一个布尔值!例var_dump($stu2 instanceof Student); //bool(true)           4.__clone()方法也是属于魔术方法! 触发情况:__当一个对象被克隆的时候自动调用该魔术方法!功能:对克隆出来的新对象进行相关的初始化! 三、MySQLDB类初步      一般类文件的命名方式为:类名.class.php--------例:MySQLDB.class.php 1.设置属性,实例化的时候对属性进行初始化 2.完成对数据库的连接三步曲(连接数据库,选择默认数据库,设置默认字符集)(构造方法) 3.销毁该对象,释放对象所占用的数据库连接资源(析构方法) 四、静态成员 (1)静态属性    1、用来定义属于类的属性。静态属性属于类,所以只占一块内存空间,每个对象都可以引用这块内存空间。       静态属性的值对于各实例是一样的,如果改变,则都改变。通常用来存储属于该类的属性。 2、声明:访问控制修饰符  static  属性名-----例: public static $total = 0;//声明一个$total的静态属性 3、访问:静态属性属于类,所以应该用类名来调用。也可以使用实例来调用 1.在类外访问 使用类名来访问类名::属性名---例:echo Student::$stu_num;//注意这有$ 通过实例来访问例:$wangwang = new Dog;     echo $wangwang::$averageLife; 2.在类内访问 使用类名来访问类名::属性名---例:echo Student::$stu_num; 通过self关键字调用例:echo self::$student;//注意self类外不能使用 (2)静态方法:所有对象所共享的方法! 1、声明:访问控制修饰符 static 方法名 2、访问:类名::方法名      静态方法的访问和静态属性的访问方式相同。在类外、类内访问同静态属性访问。           3、静态方法和非静态方法的区别  静态方法:指所有的对象共享的方法 非静态方法:是指各个对象“独自”占用的方法(尽管也只有一份) 无论采用什么方式调用静态方法,都不可以使用$this!建议用self 无论是静态方法,还是非静态方法,类和对象都可以调用!但是,我们以后编程的标准只有一个: 那就是类调用静态成员!对象调用非静态成员!切记切记!!!     class Student{         public static $stu_age;         public function set_age($age){             if (is_int($age)&&$age>=0 &&$age<=150) {                 self::$stu_age=$age;//这里设置静态变量时不能用$this,切记             } else {                 echo "非法的年龄信息";                 return false;             }         }     }     $stu=new Student;     $stu->set_age(20);//调用类中公开的接口     echo $stu::$stu_age;     //10,调用并获取静态变量     var_dump($stu);//object(Student)#1 (0) { } 五、类常量 就是指在一个类中定义的常量,和普通的常量没有什么本质的区别,只是类常量需要先找到类才能访问常量! 声明语法:const 常量名 = 常量值;例const SCHOOL="whereit"; 访问:类名::常量名-----例:echo Student::SCHOOL;在一个类的内部,类名也可以使用self来代替! 注意:类中所有的成员 一共有5种:非静态属性,非静态方法,静态方法,静态属性, 类常量, 只有非静态属性保存在对象空间里面,其他都在类的用户代码区和类空间 。 六、手动加载类文件include "./Student.class.php"; 在实际的项目中,如果一个类在多个脚本文件都需要使用的话,可以将这个类文件名字为:类名.class.php, 单独的放到一个文件内,当需要的时候,将文件加载进来即可! 方法:直接使用include_once() 将所需的类文件包含进来,或将所有的类文件导入一个文件里面,然后需要的时候将这个文件导入即可。 七、类文件的自动加载 php加载文件方式:
1、include,include_once,requice,requice_one常规加载
2、__autoload() 3、spl_autoload_register() 函数名:__autoload() 触发情况:当php找不到类文件的时候//注意触发条件,如果本页面内有该类名,无法加载     function __autoload($class_name){         if (is_file("./$class_name.class.php")) {             include_once("./$class_name.class.php");         }else{             die("./$class_name.class.php不存在");         }     }      $stu=new Studet; //本页无Student类,则会自动去Student.class.php中找Student类。 为何要使用自定义的类文件自动加载函数? 因为随着项目的扩展,可能后期会出现多个自动加载函数,这时候就出现了函数的重名问题,因此我们要自己注册自动加载函数 八-9.1注册其他的自动加载函数 实现步骤:第一步:定义一个可以加载类文件的普通函数      第二步:使用spl_autoload_register(函数名)来实现注册spl_autoload_register(‘函数名’); 注意: 1.注册一定要发生在需要某个类之前 2.可以注册多个,在需要的类文件载入成功之前,系统会依次调用 3.一旦注册成功,系统默认的__autoload就会失效,如果想继续使用,就需要像注册其他普通函数一样重新注册     function f1($class_name){         if (is_file("./$class_name.class.php")) {             include_once("./$class_name.class.php");         }else{             die("./$class_name.class.php不存在");         }     }     spl_autoload_register("f1");     $obj=new A;//本页无A类,则会自动去A.class.php中找A类。 八-9.2 注册自动加载方法 在面向对象的编程风格中,我们一般会将用户自定义的自动加载函数封装到一个类中! 1如果自动加载函数为静态方法 语法形式1为spl_autoload_register(array(类名,方法名))spl_autoload_register(array("Common","hhh")); 语法形式2为spl_autoload_register("类名::方法名")spl_autoload_register("Common::hhh"); 2如果自动加载函数为非静态方法 先实例化对象,再注册。语法形式为spl_autoload_register(array(对象,"方法名")) $stu=new Common;         spl_autoload_register(array($stu,"hhh"));      class Common{         //public static function hhh($class_name){                   public function hhh($class_name){             if (is_file("./$class_name.class.php")) {                 include_once("./$class_name.class.php");             }else{                 die("./$class_name.class.php不存在");             }         }      }     // spl_autoload_register(array("Common","hhh")); //静态方法注册         $stu=new Common;    //1实例化方法对象并注册该方法         spl_autoload_register(array($stu,"hhh"));//非静态方法注册           $obj = new A;     //2自动去A.class.php中找A类,这样就可以使用A类中的函数了。 PHP-OOP3(继承、封装、多态,重写、final、abstract、interface  一、类的继承面向对象的三大特性之一:继承性!利于代码的扩展和重用 伟大的程序员都懒!都要在两个字上下功夫: 继承:一个类从另外一个已有的类获得其成员特性,就叫作继承!extends 几个概念:派生,父类(基类)parent、子类(派生类)、扩展、单继承、继承链条 单继承:在PHP中,一个类只能继承自一个其他的类,不同同时继承多个类,单继承也是大多数面向对象语言的特性(C++支持多继承) 几点强调
    1. 属性和方法都可以被继承
    2. 继承的本质,不是把父类中的代码复制到子类的内部,而是通过继承链条,找到相应的成员!
    class Goods{//定义一个父类Goods         public $goods_id;         public $goods_name;         public $goods_price;         public function showName(){                     echo $this->goods_name;                 }     }     class Book extends Goods{         public $publisher;         public $author;     }     class Mango extends Book{//继承链条         public $system;         public $pages;        }     $book=new Book;     $mango=new Mango;     echo "<pre>";     var_dump($book,$mango);     $book->goods_name="海贼王";     $book->showName();//输出:海贼王 二、2.1多态 1、多态,从字面意思上理解,就是多种状态。 2、在面向对面语言中,多态指的是不同的对象,对同一个消息的不同响应。 3、多态,意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。 4、有继承才有多态。方法的重写可以实现多态。因此父类尽量是抽象类或者接口。 class Bird{// 定义一个Bird类         public $age;// Bird的年龄         public $sex;// Bird的性别         public function chirm(){// 鸟鸣方法             echo "叽叽喳喳...<br />";         }         public function fly(){             echo "飞呀飞呀...<br />";         } }    class Parrot extends Bird{// 鹦鹉类 重写了chirm鸟鸣方法         public function chirm(){             echo "你好你好...<br />";         } }    class Ostrich extends Bird{// 鸵鸟类 重写了fly方法         public function fly(){             $this->run();         }         public function run(){             echo "跑啊跑啊...<br />";         } }        function fly($obj){// 如果属于鸟类,则让它飞行         if($obj instanceof Bird) $obj->fly();     }     function chirm($obj){// 如果属于鸟类,则让它鸣叫         if($obj instanceof Bird) $obj->chirm();     }     //    不同的对象对同一种方法的不同反应     fly(new Ostrich());    //跑啊跑啊...     fly(new Parrot());    //飞呀飞呀...     chirm(new Ostrich());//叽叽喳喳...     chirm(new Parrot());//你好你好...   2.2重写override 1、重写也叫作覆盖,就是当子类的成员与父类的成员的名字相同的时候,从父类继承下来的成员会重新定义! 注意:重写是由继承链决定的,当子类调用一个方法的时候。如果在子类没有找到,就会接着在父类寻找。所以重写并不是真正意义上的覆盖父类方法。 在真实的项目中,一般是可以通过修改方法的名字来避免重写的! 但是,有些方法的名字是固定的,比如:构造方法,析构方法等魔术方法,所以,这种情况,重写不可避免! 2、重写的其他语法 1.如果必须要执行被重写的父类方法,必须在子类的方法中,显式的调用父类的同名方法!此时子类方法参数要加上它。      语法-----父类名::父类中的方法名-----例:Goods::_contruct($name); 2.parent不一定就代表本类的上一级父类,如果父类中没有找到相应的方法,会继续的向更上一级的父类查找!           parent::_contruct($name);---建议使用parent代替 3.当子类重写父类的方法的时候,方法的参数形式(个数),必须与父类保持一致(构造方法除外)      例:$mango=new Mango("尾田","海贼王"); 三、3.1封装面向对象的三大特性之一:封装性主要是为了实现程序的单入口    3.2访问控制修饰符 1、在PHP中,一共有三个访问控制范围的概念: 当前类内:当前代码所在的类内 继承链类内:所有在一个继承链上的类内,并且对于链上的任意的一个类,访问的范围是一样 类外:除了类内,都是类外 所以,访问控制修饰符也一共有三个: public公共的,当前类内,继承链类内和类外都可以被访问到 protected受保护的,当前类内以及继承链上的类内可以被访问到(该类或其子类) private私有的,只有当前类内可以被访问到 2、访问控制修饰符的使用原则 尽量的隐藏类的内部实现,仅仅公开一些操作接口!(接口就是对象对外部公开的操作方法) 其他原则 1.当子类重写父类的成员时,子类成员的访问控制权限不应该低于父类的访问控制权限!      若父类:public   子类:只能是public,若父类:protected 子类:可以是protected也可以是pubic 2.从形式上看,子类可以继承父类的私有成员,但是却无法使用! 3.私有成员(私有属性和私有方法)都不能被重写,但是子类还是可以定义跟父类私有成员同名的成员,但是此时,只是当作子类自身的新的成员而已! 4,虽然父类的私有方法不能被重写,但是,如果子类重新定义了一个同名的方法的时候,方法参数的形式(参数的个数)还是需要和父类保持一致!     class Student{         private $stu_age;         private $stu_name;         public function set_age($age){             if (is_int($age)&&$age>=0 &&$age<=150) {                 $this->stu_age=$age;             } else {                 echo "非法的年龄信息";                 return false;             }
        }     }     $stu=new Student;     $stu->set_age(10.5);//调用类中公开的接口     //echo $stu-> stu_age;//报错! Fatal error: Cannot access private property Student::$stu_age,改为public则可以访问     var_dump($stu);//非法的年龄信息……     //可以有效控制用户的行为--封装优点 //当set_age()10;时object(Student)#1 (2) { ["stu_age":"Student":private]=> int(10) ["stu_name":"Student":private]=> NULL },可以看到但类外不能访问 四、提高MySQLDB类的封装性 私有化属性,私有化方法 给MySQLDB类增加三个公开的方法: fetchAll得到所有的记录(比较适合查询结果是多行多列的情况) fetchRow得到一条记录(比较适合查询结果是单行的结果集) fetchColumn得到一条记录的第一个字段(比较适合查询结果是单行单列的结果集) 五、final最终类 类有两个“极端”: final类:也叫作最终类,不能被继承,只能实例化对象 final最终类其实就是实际开发过程中的一种语法上的规范! 最终方法final method 当一个类还需要继承,但是不希望该类中的某些方法被重写,可以使用最终方法。 当该类被其他的类所继承的时候,该最终方法不能被重写! 六、abstract类:抽象类,不能实例化对象,只能被继承      抽象类其实就是不完整的类,所以无法实例化一个真实的对象!需要下一级的类去实现(完善方法体)!      而继承它的类也只有两种选择:1要么完成父类(抽象类)中的抽象方法(完善方法体)2要么继续做抽象类!     abstract class Animal{         public function move(){         }     }     class Bird extends Animal{            public function move(){             echo "I can fly!<br/>";         }     }     class Snake extends Animal{            public function move(){             echo "I can creep!<br/>";         }     }     $bird=new Bird;     $bird->move();//I can fly!     $snake=new Snake;     $snake->move();//I can creep! 特别强调
  1. 如果一个类继承自一个抽象类,而其自身不是一个抽象类,则必须实现父类中的所有的抽象方法!
  2. 抽象类中,不但可以包括抽象方法,还可以包括其他任意的普通成员(属性、常量、非抽象方法),都可以被子类所继承
抽象类的作用
  1. 可以完成普通类的继承,为其他的类提供公共的代码!
  2. 抽象类往往用于规定子类中必须要完成的方法或者成员,规定子类的方法结构,有时候为了保证完成一系列功能相似的多种操作类的结构一致,我们要求这些类都继承自一个相同的抽象类!
七、interface接口 在PHP中定义一个接口,其实就是一种纯粹的规范或规定,规定该接口的下级类必须要“实现”的公共方法! 接口不是类!接口是类的规范,类又是对象的规范! 在一个接口中,只能出现两种成员: 接口常量,抽象方法:没有方法体的方法,但是此时,抽象方法中所有方法必须声明为public(与抽象类中的抽象方法不同)      要使接口作用到类上,就必须使用implements关键字,意思为“实现”,其实和继承的本质是一样的! 当一个类“实现”一个接口的时候,也只有两种选择:
  1. 实现该接口中所有的公开的抽象方法(完善方法体)
  2. 如果该类没有实现接口中的部分(或全部)公开的抽象方法,就应该把该类声明成抽象类,然后等待更下一级的类去实现!此时,没有被实现的方法最好继续声明成抽象方法!
    interface I_animal{         public function move();         public function eat();     }     interface I_shengwu{         public function sleep();     }     abstract class Human implements I_animal,I_shengwu{//接口支持多实现。这也是接口和抽象方法的本质区别。         public function move(){}         public function eat(){}         abstract public function sleep();     } 接口与抽象类的比较
  1. 接口不是类(需要用interface来进行声明,需要其他类用implements实现 ),但抽象类是类(需要class进行声明,需要用extends继承 )
  2. 从逻辑或结构上看,接口可以看成是抽象类的一个“子集”,比抽象类更“抽象”,只有抽象方法和常量没有其他的普通的方法
  3. 类只支持单继承,而接口支持多实现。这也是接口和抽象方法的本质区别。
     4.接口与抽象类都可以作为其他类的规范,都可以规定下级类的内部结构,但是在真实的项目中,接口使用的要多一些!     interface I_USB{         const WIDTH=10;         const HEIGHT=4;         public function load();         public function run();     }     class MOuse implements I_USB{         public function load(){             echo "加载鼠标驱动<br/>";         }         public function run(){             echo "鼠标运行<br/>";         }     }     class Disk implements I_USB{         public function load(){             echo "加载移动硬盘驱动<br/>";         }         public function run(){             echo "移动硬盘运行<br/>";         }     }     $mouse=new MOuse;     $mouse->run();//鼠标运行 PHP-OOP4伪重载、后期静态绑定 、单例模式、工厂模式、数据存储:系列与反系列 一、PHP中重载(伪重载) 为一个不存在的属性赋值的时候,PHP触发不同的方法,于是支持将该属性重新载入到当前的对象的内部,这种现象就叫作属性重载! PHP是可以采取相应的操作来处理对不可访问的成员的操作的控制!(以上是系统的默认行为) PHP不支持重载,但是可以利用其它方式实现类似重载的功能。     class Student{         public $stu_id;         public $stu_name;     }     $stu=new Student;     $stu->stu_id=9527;     $stu->stu_name="华安";     $stu->stu_age=25;//本来没有age值,php自动以类似重载方法插入该公共属性和值     var_dump($stu); object(Student)#1 (3) { ["stu_id"]=> int(9527) ["stu_name"]=> string(6) "华安" ["stu_age"]=> int(25) } 所以,根据所处理的成员不同,重载又分成两种情况: 1、属性重载 根据对不可访问的属性的操作方式不同,系统分别由不同的魔术方法来处理: 一共有四个魔术方法:主要作用是让用户取得处理控制权 1为不可访问的属性赋值: __set() 该魔术方法需要两个参数:该不可访问的属性的属性名和属性的值 一旦定义了__set()魔术方法,为不可访问的属性赋值的时候,就会自动的执行该方法,此时,处理权就交给用户自己了! 2获得不可访问的属性的值:  __get() 一旦定义了__get()魔术方法,获取不可访问的属性的值的时候,就会自动的执行该方法,此时,处理权就交给用户自己了! 该魔术方法,只需要一个参数,就是该属性的属性名! 注意:__get和__set两个方法往往在真实的项目中都是成对出现的!而且,往往就是利用这两个方法批量的对对象的私有属性进行处理! 3删除不可访问的属性:  __unset() 但是,如果该属性是不可访问的(比如private或不存在),则会自动执行__unset方法,究竟是否可以删除成功,还是取决于__unset的内部实现! 该方法也只需要一个参数,就是当前删除的属性名! 4判断不可访问的属性是否存在:  __isset() 如果该属性是不可访问的属性,判断这个属性是否存在的时候,会自动触发该方法的执行! 同样的,该方法也需要一个参数,技术当前需要判断的属性名! 2、方法重载:指访问不可访问的方法的时候的处理方式! 方法重载是通过两位的两个魔术方法来完成的: __call() 当调用一个不可访问的对象方法(非静态方法),会自动的执行该魔术方法! 参数一:方法名,string型,参数二:array型,因为参数的个数不确定,只能把所有的参数都放到一个数组里面 假如这个方法什么都不做: 当调用一个不可访问的类方法(静态方法)的时候,会自动执行该魔术方法,定义这个方法的时候,需要在方法名 的前面加上static关键字,因为该方法应该是一个静态方法!     class Student{         private $stu_id;         private $stu_name;         private $stu_age;         private $stu_money;                public function __set($name,$value){//增加__set方法             $allow_set=array("stu_id","stu_money","stu_name","stu_age");             if (in_array($name, $allow_set)) {                 $this->$name=$value;             }         }         public function __get($name){//增加__get方法             $allow_get=array("stu_id","stu_name");             if (in_array($name, $allow_get)) {                 return $this->$name;             }else{                 return false;             }         }            public function __unset($name){//增加__unset方法             $allow_unset=array("stu_age","stu_money");             if (in_array($name, $allow_unset)) {                 unset($this->$name);             }else{                 return false;             }                    }         public function __isset($name){//增加__isset方法             $allow_isset=array("stu_id","stu_money","stu_name","stu_age");             if (in_array($name, $allow_isset)) {                 return true;             }else{                 return false;             }                    }         public function __call($name,$arr){//当调用一个不可访问的非静态方法时,自动执行             // var_dump($arr);             echo "对不起,您调用的非静态方法不存在<br/>";         }         public static function __callstatic($name,$arr){//当调用一个不可访问的静态方法时,自动执行             // var_dump($arr);             echo "对不起,您调用的静态方法不存在<br/>";         }            }     $stu=new Student;     $stu->stu_id=9527;     $stu->stu_name="华安";     $stu->stu_age=25;     $stu_teacher="大虎";     echo "<pre>";     var_dump($stu);     // echo $stu->stu_age;     unset($stu->stu_age);     var_dump($stu);//stu_age属性和值被删除     var_dump(isset($stu->stu_name));//bool(true)     $stu->showName(10,20);//对不起,您调用的非静态方法不存在     Student::showName();//对不起,您调用的静态方法不存在 一个小案例(伪重载):设计一个数学类
    class Math{      //PHP不支持重载,但是可以利用其它方式实现类似重载的功能。         public function __call($name,$arr){             if ($name=="f1") {//判断用户调用的方法是否为f1                 $length=count($arr);//根据参数的额个数进行业务逻辑处理                 if ($length<1||$length>3) {                     echo "非法的参数个数";                 }elseif ($length==1) {                     return $arr[0]*$arr[0];                 }elseif ($length==2) {                     return $arr[0]*$arr[0]+$arr[1]*$arr[1];                 }elseif ($length==3) {                     return $arr[0]*$arr[0]*$arr[0]+$arr[1]*$arr[1]*$arr[1]+$arr[2]*$arr[2]*$arr[2];                 }             }         }     }     $obj=new Math;     echo $obj->f1(10); //100     echo "<br/>";     echo $obj->f1(10,20); //500     echo "<br/>";     echo $obj->f1(10,20,30);//36000 二、MySQLDB类的重载 完善属性重载:完善__set(),完善__get(),完善__unset(),完善__isset() 完善方法重载:MySQLDB类的单例模式 第一步:增加一个私有的静态属性,用于保存对象 第二步:把构造方法私有化 第三步:增加一个获得单例的公共方法 第四步:私有化克隆魔术方法 三、后期静态绑定 1、$this是不是永远代表其代码所在类直接实例化出来的对象?不是,$this是要根据上下文的执行环境来决定的! 2、self是不是永远代表其代码所在类的类名?回答:是 总结一下static的功能,一共有三个了:
    1. 定义静态局部变量(和变量的生命周期相关)
    2. 定义静态成员(静态方法和静态属性)
    3. 代表“当前类”
总结,目前代表类的关键字一共有几个了?一共有三个: self当前类(在预编译阶段绑定),在哪就是哪的类。 static当前类(后期静态绑定),谁用就是谁的类。 parent代表父类 什么是设计模式? 所谓的设计模式,并不是一种新的语法,而是人们在实际的应用中面对某种特定的情形而设计出来的某种常见的有效的解决方案,只是经验的总结! 四、单例模式 通过某些技巧从语法上使得一个类只能开辟一个对象空间的话,就可以节省相应的对象资源,这种模式就叫作单例模式! 四步走、实现单例模式的最典型的做法:也叫作“三私一公”!     class MySQLDB{         //3增加一个私有属性,用于保存第一次实例出来的对象         private static $instance;         //1私有化构造方法,阻止无限地new实例出来         private function __construct(){                    }         //2增加静态公开方法,去生产实例         public static function getInstance(){             if(!self::$instance instanceof self){                 self::$instance=new self;             }             return self::$instance;         }         //4私有化__clone方法         private function __clone(){         }     }     // $obj=new MySQLDB;     // var_dump($obj);// Fatal error: Call to private MySQLDB::__construct() from invalid context in     $db1=MySQLDB::getInstance();     var_dump($db1);// object(MySQLDB)#1 (0) { }     $db2=MySQLDB::getInstance();     var_dump($db2);// object(MySQLDB)#1 (0) { }     // $db3=clone $db2;     // var_dump($db3);// Fatal error: Call to private MySQLDB::__clone() from context  五、工厂模式 工厂模式的含义就是:设计一个类(此时这个类可以叫作“工厂类”),该类的作用就是帮助其他的类“生产”对象, 也就是说,只要传递给这个“工厂”一个类名,就可以得到一个相应的对象!   //利用工厂模式生产对象      class A{     }     class B{     }     class Factory{         public static function getInstance($class_name){             return new $class_name;//可变对象         }     }     echo "<pre>";     //利用工厂得到对象     $aaa=Factory::getInstance("A");     var_dump($aaa);//object(A)#1 (0) {}     $bbb=Factory::getInstance("B");     var_dump($bbb);//object(B)#2 (0) {} 利用工厂方法,生产单例对象 但是这里的单例,实现的方式并不是“三私一公”!     class DanFactory{         private static $instance=array();         public static function getInstance($class_name){             if (file_exists("./".$class_name.".class.php")) {                 include_once "./".$class_name.".class.php";                 if (!isset(self::$instance[$class_name])|| !self::$instance[$class_name] instanceof $class_name) {                     self::$instance[$class_name]=new $class_name;                 }                 return self::$instance[$class_name];             }else{                 die("系统错误,没有找到相关的类!");             }                    }     }     echo "<pre>";     //利用工厂得到对象     $aaa=DanFactory::getInstance("A");     var_dump($aaa);//object(A)#1 (0) {}     $bbb=DanFactory::getInstance("B");     var_dump($bbb);//object(B)#2 (0) {}     $ccc=DanFactory::getInstance("A");     var_dump($ccc);//object(A)#1 (0) {}
六、1、数据的存储 也就是数据被持久化!一般的,可以将数据存放到数据库或者文件磁盘介质中! 当PHP脚本运行结束的时候,内存中的数据都会丢失,脚本的资源也都会消失(包括脚本中的数据),所以,如果想 实现数据存储,就应该在脚本运行结束之前进行数据的持久化! 在将数据自动转换成字符串的时候,同时在字符串内记录原数组的值和类型等相关的信息,目的就是在 得到数据的时候,能根据存储的信息(包含数据类型)转换成原始数据! 这个工作就是由数据的序列化与反序列化来完成的! 2、数据的序列化与反序列化 数据的序列化: 将原始数据转换成可以用于保存和传输的字符串数据!(不仅仅记录原数组的值,还记录原数据的类型等相关信息) serialize():序列化---在数据存放到文件之前先进行序列化: 数据的反序列化:将序列化后的字符串数据,转换成原始数据! unserialize():反序列化---在读取数据之前进行反序列化: 注意: 数据的序列化与反序列化适用于除了资源类型之外的任何的数据类型!包括对象和字符串本身! 1在将对象存储到文件之前进行序列化操作,在输出对象之前进行反序列化时对象数据有问题? 反序列化的时候,也需要先找到对象所属的类,如果找不到,则对象会被反序列化成一个名字叫作__PHP_Incomplete_Class的类!这是一个系统预定义的类! 解决方案:只需要在反序列化的时候找到这个对象所属的类就行了:手动载入!或自动载入! 2序列化的时候,资源型的属性$link被转换成了整型数据0! 解决方法:在序列化的时候不存储资源型数据,在反序列化的时候再打开相应的资源!        __sleep() 是在序列化一个对象的时候自动调用!该方法用于规定哪些属性应该被序列化,实现的方式为: 返回一个索引数组,数组内的元素为需要被序列化的属性名的集合! __wakeup()是在一个对象反序列化的时候自动调用的!主要用来对对象进行相关的初始化操作!
    //在MySQLDB类中增加魔术方法__sleep()和__wakeup()     public function __sleep(){         return array("host","port","user","pass","charset","dbname");     }     public function __wakeup(){//初始化数据库三部曲         $this->my_connect();//连接数据库         $this->my_charset();//选择默认字符集         $this->my_dbname();//选择默认的数据库     }
    function __autoload($class_name){//系列化         if (file_exists("./".$class_name.".class.php")) {             include_once "./".$class_name.".class.php";         }else{             die("系统错误,没有找到相关的类!");         }     }     $arr=array(         "pass"=>"123456",         "dbname"=>"whereit"         );     $data=MySQLDB::getInstance($arr);     echo "<pre>";     var_dump($data);     $s_data=serialize($data);//写入文件之前先将数据进行序列化     echo file_put_contents("./38.txt",$s_data);//返回值是写入的字符串的长度
    function __autoload($class_name){//在反序列化的时候找到这对象所属的类就行:手动载入!自动载入!         if (file_exists("./".$class_name.".class.php")) {             include_once "./".$class_name.".class.php";         }else{             die("系统错误,没有找到相关的类!");         }     }     $data=file_get_contents("./38.txt");     $u_data=unserialize($data);//在读数据之前进行反序列化     echo "<pre>";     var_dump($u_data); PHP-OOP5(类的魔术方法、魔术常量、对象遍历,类型约束,类和对象的相关函数 ,命名空间) 一、魔术方法:名字由系统定义,而方法体由用户自己编写的方法! 最大特点是:不需要用户手动调用,而是当特定的情况发生时,系统自动调用相关的魔术方法! 注意:__autoload不算是魔术方法,但是其语法形式很类似于魔术方法! 类的魔术方法 __construct(),__destruct(),__clone(),__get(),__set(),__unset(),__isset(),__call(),__callstatic(),__sleep(),__wakeup() __invoke() 当我们把对象当做一个函数(或方法)来调用的时候,会自动执行该魔术方法 之所以可以使用匿名函数$func闭包对象成功地调用函数,就是因为闭包对象里面有一个__invoke魔术方法 __toString() 当我们把一个对象当成是一个字符串来使用的时候,会自动的执行该模仿方法! public function __toString(){ return serialize($this);}//返回值可以是该对象序列化成字符串的结果! 二、类的魔术常量 __LINE__ 文件中的当前行号 __TRAIT__trait的名称,trait是PHP实现代码复用的一种方法,类似于接口。(5.4开始支持) __CLASS__:代表的是当前的类名! 注意与self的区别:例return new __CLASS__;是错误的,无法new      self是指该类的本身(一种结构,不仅仅包括类名),而__CLASS__只是一个类名(类名只是类的一部分!) 但是:$classname=__CLASS__; return new $classname;是可以new的,这里是可变类名的一种语法。 __METHOD__:代表当前的方法名!---在类里echo __METHOD__;//结果A::showCLassName __FILE__文件的完整路径和文件名, __DIR__文件所在的目录 __FUNCTION__函数的名称 __NAMESPACE__当前命名空间的名称 三、对象的遍历使用foreach语句! 对象的自定义遍历
  1. 对象的遍历受属性的访问控制的限制!
  2. 对象毕竟是有“生命力”的,可以自定义遍历!
对象的自定义遍历,就是指使用foreach遍历某一个类的对象的时候,可以在foreach的各个阶段,调用相应的自定义的方法来完成! 对象的自定义遍历,需要用到接口化编程 ,实现了一个名叫Iterator的系统预定义接口,那么我们在使用foreach遍历该类的对象的时候,就可以在foreach的各个阶段,调用相应的自定义的方法来实现! Iterator里面有五个抽象方法:1current — 返回当前元素,2key — 返回当前元素的键,3next — 向前移动到下一个元素 4rewind — 返回到迭代器的第一个元素,5valid — 检查当前位置是否有效     header("Content-type:text/html;charset=utf-8"); //对象的自定义遍历     class Person implements Iterator{         private $position = 0;         public $a;         public $e = array(1,2,3,4,5);         // 返回到迭代器的第一个元素         public function rewind(){             $this->position = 0;         }         // 判断是否有效         public function valid(){             return isset($this->e[$this->position]);         }         // 返回值         public function current(){             return $this->e[$this->position];         }         // 返回键         public function key(){             return $this->position;         }         // 指针下移         public function next(){             $this->position++;         }     }     $obj = new Person;     foreach($obj as $k=>$v){         echo $k,"=>",$v,"<br />";     }//0=>1,1=>2...4=>5 四、类型约束 数组类型约束 就是强制的要求函数或者方法的形参是一个数组!---数组类型约束  (array 参数) 对象类型约束 就是强制要求函数的实参必须是某一个类的对象!---对象类型约束 (类名 参数) 五、类和对象的相关函数 class_exists()---例:var_dump(class_exists("A"));//bool(true)检查类A是否已定义 interface_exists()---例:var_dump(interface_exists("I_test"));//bool(true) method_exists()---例:$obj=new A;var_dump(method_exists($obj,"f1"));//bool(true) 两个参数:第一个参数是对象变量,第二个参数是方法的名字 get_class():获得一个对象所属的类名!---参数一个对象 get_parent_class()获得对象或类的父类!---参数一个对象 get_class_methods()作用就是返回该类的方法!---参数是一个类,返回的是一个数组。 注意:在类外只能打印出公共方法,在类内可以打印出所有方法。 公开的静态方法和公开的非静态方法都可以被返回,但是无法返回受保护的和私有的方法名(在类外执行的时候)! get_class_vars()函数的参数也只有一个,也是类名,能返回公开的属性! is_object()判断一个变量是否为一个对象! 六、命名空间概述 一种用来将内存逻辑划分的功能,用来区分同名的类,函数和常量 1、基本语法:namespace 空间名字; 其中,空间的名字尊重基本标识符的命名规则(以字母、数字和下划线构成,不能以数字开头) 几点需要特别注意的地方: 1如果一个脚本的开始需要定义命名空间,则必须在脚本最开始处定义!(例<?php ?>标签前不能有空格) 2一个脚本周期内,可以定义多个命名空间,并且不同的空间内可以定义相同名称的函数、常量和类! 2、空间成员 一个命名空间的内部可以有任意的PHP代码,但命名空间本身只“管辖”三种空间成员:常量、函数和类,其他的都不属于空间成员!例:变量不属于空间成员! 注意:命名空间内部除了空间成员(类、常量和函数)受限制之外,其他的代码都是该怎么执行就怎么执行,不存在任意的区别! 3、子空间 同计算机的目录可以存在子目录一样,内存中的空间可以存在子空间! 目录:A/B/C,其中,C就是B目录的子目录,而B又是A的子目录 空间:namespace ABC;其中空间C就是空间B的子空间,而空间B又是空间A的子空间(注意使用反斜杠),      其表示的含义是创建了一个名字为C的子空间!并且A空间和B空间也一起创建了! 注意:子空间不能直接访问父空间的内容。因为它们只是逻辑上的划分。 4、空间成员的访问:注意使用反斜杆 PHP提供了三种访问空间成员的方法:非限定名称方法、限定名称访问和完全限定名称访问! 1非限定名称访问 所谓的非限定名称访问,就是指在访问空间成员的时候,没有指定具体的空间的名字,我们前面的访问方式都是属于非限定名称访问! 2限定名称访问 就是从当前空间开始,访问其子空间的成员! 语法形式:子空间名空间成员名-----例:namespace AB; CgetName(); 3完全限定名称访问 就是直接从根空间(类比网站根目录)开始绝对路径访问
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。