PHP基础知识笔记(面向对象)

面向对象编程        面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构,OOP的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个目标:重用性、灵活性和扩展性。

对象:
        万物皆对象(世间万物,皆对象)
        对象是有属性,方法组成的数据(只要是对象就有属性和方法)
        为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。面向对象一直是软件开发领域内比较热门的话题,首先,面向对象符合人类看待事物的一般规律。其次,采用面向对象方法可以使系统各部分各司其职、各尽所能。为编程人员敞开了一扇大门,使其编程的代码更简洁、更易于维护,并且具有更强的可重用性。
        有人说PHP不是一个真正的面向对象的语言,这是事实。PHP 是一个混合型语言,你可以使用OOP,也可以使用传统的过程化编程。然而,对于大型项目,你可能需要在PHP 中使用纯的OOP去声明类,而且在你的项目里只用对象和类。
类的概念:
        类是具有相同属性和服务的一组对象的集合。它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和服务两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性说明和服务说明两个主要部分。
对象的概念:
        对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。从更抽象的角度来说,对象是问题域或实现域中某些事物的一个抽象,它反映该事物在系统中需要保存的信息和发挥的作用;它是一组属性和有权对这些属性进行操作的一组服务的封装体。客观世界是由对象和对象之间的联系组成的。
类与对象的关系
        就如模具和铸件的关系。类的实例化结果就是对象,而对一类对象的抽象就是类。类描述了一组有相同特性(属性)和相同行为(方法)的对象。
        面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,所以我们首先要做的就是如何来声明类,做出来一个类很容易,只要掌握基本的程序语法定义规则就可以做的出来,那么难点在那里呢?一个项目要用到多少个类,用多少个对象,在那要定义类,定义一个什么样的类,这个类实例化出多少个对象, 类里面有多少个属性, 有多少个方法等等,这就需要通过在实际的开发中就实际问题分析设计和总结了。
类的定义:
class 类名{
    属性;
    方法;
}
实例化:$对象名称 = new 类名称();
对象成员:对象 -> 属性;对象 -> 方法;
        使用关键字class和后面加上一个你想要的类名以及加上一对大括号,这样就是一个类的结构的定义,在里面写上代码就可以了。

        通过在类定义中声明函数,这样就创建了类的方法。声明的函数前面加上关键字“public、protected、private”。

访问权限

public    公共的(在外部可以访问);
protected    受保护的(只能在类里面和子类中访问);

private    私有的(只能在类里面访问,不能在子类或外部访问)。

        public 公有修饰符,类中的成员将没有访问限制,所有的外部成员都可以访问(读和写)这个类成员(包括成员属性和成员方法)。
        private 私有修改符,被定义为private的成员,对于同一个类里的所有成员是可见的,即没有访问限制;但对于该类的外部代码是不允许改变甚至读操作,对于该类的子类,也不能访问private修饰的成员。
        protected保护成员修饰符,被修饰为protected的成员不能被该类的外部代码访问。
但是对于该类的子类有访问权限,可以进行属性、方法的读及写操作,该子类的外部代码包括其的子类都不具有访问其属性和方法的权限。
        在子类覆盖父类的方法时也要注意一点,子类中方法的访问权限一定不能低于父类被覆盖方法的访问权限,也就是一定要高于或等于父类方法的访问权限。
        例如,如果父类方法的访问权限是protected,那么子类中要覆盖的权限就要是protected和public,如果父类的方法是public那么子类中要覆盖的方法只能也是public,总之子类中的方法总是要高于或等于父类被覆盖方法的访问权限。


privateprotectedpublic
同一个类中  √  
  √  
  √  
类的子类中
  √  
  √  
所有的外部成员

  √  
当定义好类后,我们使用new关键字来生成一个对象。
$对象名称 = new 类名称();
对象->属性 $p1->name;
$p2->age; 
$p3->sex;
对象->方法 $p1->say();
$p2->run();
        因为对象里面的所有的成员都要用对象来调用,包括对象的内部成员之间的调用,所以在PHP里面给我提供了一个本对象的引用$this,每个对象里面都有一个对象的引用$this来代表这个对象,完成对象内部成员的调用, this的本意就是“这个”的意思,上面的实例里面,我们实例化三个实例对象$P1、 $P2、 $P3,这三个对象里面各自存在一个$this分别代表对象$p1、$p2、$p3 。
实例:
<?php
class Person {
    // 下面是人的成员属性
    public $name; // 人的名字
    public $sex; // 人的性别
    public $age; // 人的年龄
    // 下面是人的成员方法
    function say() { // 这个人可以说话的方法
        echo “我的名字叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;
    }
    functionrun() { // 这个人可以走路的方法
        echo "这个人在走路";
    }
}
$p1 = new Person(); // 创建实例对象$p1
$p2 = new Person(); // 创建实例对象$p2
$p3 = new Person(); // 创建实例对象$p3
?>
在PHP中构造函数和析构函数是固定的。
构造函数
构造函数可以接受参数,能够在创建对象时赋值给对象属性
构造函数可以调用类方法或其他函数
构造函数可以调用其他类的构造函数
析构函数
析构函数是在销毁对象时,自动调用,不能显示的调用。
析构函数不能带参数。
对象编程三大特性:封装    继承    多态
        所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
        封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
目的:使类更加安全
步骤:
1、成员变量变成private(私有的)
2、设置方法/调用方法
3、在方法中增加限制
        所谓继承是指可以让某个类型的对象获得另一个类型的对象的属性的方法,它支持按级分类的概念。
        继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
子类与父类的属性与方法
子类继承父类的所有内容,但父类中的private部分不能直接访问
子类中新增加的属性和方法是对父类的扩展
子类中定义的与父类同名的属性是对父类属性的覆盖,同名的方法也是对父类方法的覆盖
所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。
        多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
        当父类引用指向子类实例的时候,由于子类对父类的方法进行了重写,父类引用在调用该方法的时候表现出的不同,称为多态
        多态性是指在父类中定义的属性或行为被子类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在父类及其各个子类中具有不同的语义。就是说同一种方法在子类与父类中执行的结果不同。
条件:
1.要有继承
2.父类引用指向子类实例
3.要有重写
4.调重写的方法
五大基本原则
        单一职责原则SRP(Single Responsibility Principle)是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
        开放封闭原则OCP(Open-Close Principle)一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。
        替换原则(the Liskov Substitution Principle LSP)子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。
        依赖原则(the Dependency Inversion Principle DIP) 具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。
        接口分离原则(the Interface Segregation Principle ISP)模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来
魔术方法
1.__construct()          实例化对象是被自动调用。当__construct和以类名为函数名的函数 同时存在时调用__construct,另一个不背调用。类名为函数名的函数为老版的构造函数。
2.__destruct()        当删除一个对象或一个对象操作结束是被调用。
3.__call()        对象调用某个方法。若方法不存在,这调用__call 这个方法
4.__get()        读取一个对象属性,如果对象属性是私有的会调用它
5.__set()        给一个对象属性赋值时如果属性是私有的会调用它
6.__toString()        打印一个对象的时候会被调用。
7.__clone()        克隆对象时被调用,如:$a=new test(); $a1=clone $a;
8.__sleep()        Serialize 之前被调用,若对象比较大,想删减一点东西在序列化可以用它。
9.__wakeup()        Unserialize时被调用,做些对象的初始化工作。
10.__isset()        检测一个对象的属性是否存在如果 检测的属性是私有的时候会被调用。
11.__unset()        删除一个对象属性时如果 删除的对象属性是私有的会被调用
12.__set_state()        调用var_export时,被调用。用__set_state的返回值做为var_export的返回值。

13.__autoload()        实例化一个对象时,如果对应的类不存在,则该方法被掉用。

方法重载
<?
class Student extends Person {
    public $school; // 学生所在学校的属性 
    // 这个学生学习的方法
    function study() {
        echo "我的名子叫:" . $this->name . " 我正在" . $this->school . " 学习";
    } 
    // 这个学性可以说话的方法, 说出自己所有的属性,覆盖了父类的同名方法
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . " 我在" . $this->school . "上学";
    }
}

?>

        “Student”子类里覆盖了继承父类里面的”say()”的方法,通过覆盖实现了对“方法”扩展。但是,像这样做虽然解决了上面说的问题,但是在实际开发中,一个方法不可能就一条代码或是几条代码,比如说“Person”类里面的“say()”方法有里面有100条代码,如果我们想对这个方法覆盖保留原有的功能外加上一点点功能,就要把原有的100条代码重写一次,再加上扩展的几条代码,这还算是好的,而有的情况,父类中的方法是看不见原代码的,这个时候你怎么去重写原有的代码呢?也有解决的办法,就是在子类这个方法中可以调用到父类中被覆盖的方法,也就是把被覆盖的方法原有的功能拿过来再加上自己的一点功能,可以通过两种方法实现在子类的方法中调用父类被覆盖的方法:
一种是使用父类的“类名::“来调用父类中被覆盖的方法;

一种是使用“parent::”的方试来调用父类中被覆盖的方法;

        用户可能会发现自己写的代码访问了父类的变量和函数。如果子类非常精炼或者父类非常专业化的时候尤其是这样。不要用代码中父类文字上的名字,应该用特殊的名字parent,它指的就是子类在 extends 声明中所指的父类的名字。这样做可以避免在多个地方使用父类的名字。如果继承树在实现的过程中要修改,只要简单地修改类中 extends 声明的部分。

        同样,构造方法在子类中如果没有声明的话,也可以使用父类中的构造方法,如果子类中重新定义了一个构造方法也会覆盖掉父类中的构造方法,如果想使用新的构造方法为所有属性赋值也可以用同样的方式。

final关键字

使用final关键标记的类不能被继承;
final只能修饰成员方法或类,不能使用final来修饰成员属性。

这个关键字只能用来定义类和定义方法,不能使用final这个关键字来定义成员属性。

<?php
final class Person {
    function say() { 
    }

class Student extends Person {
    function say() {
    }
}
?>
会出现下面错误:

Fatal error: Class Student may not inherit from final class (Person)//致命错误:类学生不能继承最终类(人)

使用final关键标记的方法不能被子类覆盖,是最终版本;

<?php
class Person {
    final function say() {
     } 

class Student extends Person {
    function say() {
     }
}
?>
会出现下面错误:

Fatal error: Cannot override final method Person::say()//致命错误:不能重写最终方法人::

static和const关键字

        static关键字是在类中描述成员属性和成员方法是静态的static成员能够限制外部的访问,因为static的成员是属于类的,是不属于任何对象实例,是在类第一次被加载的时候分配的空间,其他类是无法访问的,只对类的实例共享,能一定程度对类该成员形成保护;
        类里面的静态方法只能访问类的静态的属性,在类里面的静态方法是不能访问类的非静态成员的,原因很简单,要想在本类的方法中访问本类的其它成员,需要使用$this这个引用,而$this这个引用指针是代表调用此方法的对象,静态的方法是不用对象调用的,而是使用类名来访问,所以根本就没有对象存在,也就没有$this这个引用了,没有了$this这个引用就不能访问类里面的非静态成员,又因为类里面的静态成员是可以不用对象来访问的,所以类里面的静态方法只能访问类的静态的属性,即然$this不存在,在静态方法中访其它静态成员我们使用的是一个特殊的类“self”; self和$this相似,只不过self是代表这个静态方法所在的类。所以在静态方法里,可以使用这个方法所在的类的“类名“,也可以使用“self”来访问其它静态成员,如果没有特殊情况的话,通常使用后者,即“self::成员属性”的方式。

        const是一个定义常量的关键字,在PHP中定义常量使用的是“define()”这个函数,但是在类里面定义常量使用的是“const”这个关键字,类似于C中的#define如果在程序中改变了它的值,那么会出现错误,用“const”修饰的成员属性的访问方式和“static”修饰的成员访问的方式差不多,也是使用“类名”,在方法里面使用“self”关键字。但是不用使用“$”符号,也不能使用对象来访问。

__toString()方法

        类里面声明“__”开始的方法名的方法(PHP给我们提供的),都是在某一时刻不同情况下自动调用执行的方 法,“__toString()”方法也是一样自动被调用的,是在直接输出对象引用时自动调用的, 前面讲过对象引用是一个指针,比如 说:“$p=new Person()“中,$p就是一个引用,不能使用echo 直接输出$p,这样会输出“Catchable fatal error: Object of class Person could not be converted to string”这样的错误,如果你在类里面定义了“__toString()”方法,在直接输出对象引用的时候,就不会产生错误,而是自动调用了”__toString()”方法,输出“__toString()”方法中返回的字符,所以“__toString()”方法一定要有个返回值(return 语句)。

<?php
// Declare a simple class
class TestClass {
    public $foo;  
    public function __construct($foo) {
        $this->foo = $foo;
    }
    // 定义一个__toString方法,返加一个成员属性$foo
    public function __toString() {
        return $this->foo;
    }
$class = new TestClass('Hello'); 
// 直接输出对象
echo $class;

?>

克隆对象

        有的时候需要在一个项目里面,使用两个或多个一样的对象,如果你使用“new”关键字重新创建对象的话,再赋值上相同的属性,这样做比较烦琐而且也容易出错,所以要根据一个对象完全克隆出一个一模一样的对象,是非常有必要的,而且克隆以后,两个对象互不干扰。
        PHP4定义了一个特殊的方法名“__clone()”方法,是在对象克隆时自动调用的方法,用“__clone()”方法将建立一个与原对象拥有相同属性和方法的对象,如果想在克隆后改变原对象的内容,需要在__clone()中重写原本的属性和方法, “__clone()”方法可以没有参数,它自动包含$this和$that两个指针,$this指向复本,而$that指向原本。

<?
class Person {
    // 下面是人的成员属性
    var $name;  // 人的名子
    var $sex;   // 人的性别
    var $age;   // 人的年龄
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
    // 对象克隆时自动调用的方法, 如果想在克隆后改变原对象的内容,需要在__clone()中重写原本的属性和方法
    function __clone() {
        // $this指的复本p2, 而$that是指向原本p1,这样就在本方法里,改变了复本的属性。
        $this->name = "我是假的 $that->name";
        $this->age = 30;
    }
}
 $p1 = new Person("张三", "男", 20);
$p2 = clone $p1;
$p1->say();
$p2->say();

?>

__call()方法
        在程序开发中,如果在使用对象调用对象内部方法时候,调用的这个方法不存在那么程序就会出错,然后程序退出不能继续执行。
        那么可不可以在程序调用对象内部不存在的方法时,提示调用的方法及使用的参数不存在,但程序还可以继续执行,这个时候就要使用在调用不存在的方法时自动调用的方法“__call()”。
        下面加上“__call()”方法,这个方法有2个参数,第一个参数为调用不存在的方法过程中,自动调用__call()方法时,把这个不存在的方法的方法名传给第一个参数,第二个参数则是把这个方法的多个参数以数组的形式传进来。

<?php
// 这是一个测试的类,里面没有属性和方法
class Test {
    // 调用不存的方法时自动调用的方法,第一个参数为方法名,第二个参数是数组参数
    function __call($function_name, $args) {
        print "你所调用的函数:$function_name(参数:";
        print_r($args);
        echo ")不存在!<br>";
    }
}
// 产生一个Test类的对象
$test = new Test(); 
// 调用对象里不存在的方法
$test->demo("one", "two", "three");
// 程序不会退出可以执行到这里
echo "this is a test<br>";

?>

抽象方法和抽象类

什么是抽象方法?
        在类里面定义的没有方法体的方法就是抽象方法,所谓的没有方法体指的是,在方法声明的时候没有大括号以及其中的内容,而是直接在声明时在方法名后加上分号结束,另外在声明抽象方法时还要加一个关键字“abstract”来修饰。
什么是抽象类呢?
        只要一个类里面有一个方法是抽象方法,那么这个类就要定义为抽象类,抽象类也要使用“abstract”关键字来修饰;在抽象类里面可以有不是抽象的方法和成员属性,但只要有一个方法是抽象的方法,这个类就必须声明为抽象类,使用”abstract”来修饰。
抽象类怎么使用呢?

        最重要的一点就是抽象类不能产生实例对象, 所以也不能直接使用,前面多次提到过类不能直接使用,使用的是通过类实例化出来的对象,那么抽象类不能产生实例对象声明抽象类有什么用呢?将抽象方法做为子类重载的模板使用的,定义抽象类就相当于定义了一种规范,这种规范要求子类去遵守,子类继承抽象类之后,把抽象类里面的抽象方法按照子类的需要实现。子类必须把父类中的抽象方法全部都实现,否则子类中还存在抽象方法,那么子类还是抽象类,还是不能实例化类;为什么非要从抽象类中继承呢?因为有的时候要实现一些功能就必须从抽象类中继承,否则这些功能你就实现不了,如果继承了抽象类,就要实现类其中的抽象方法。

<?
abstract class Demo {
    public $test;
    abstract function fun1();
    abstract function fun2();
    function fun3() {
        ...
    }
}
$demo = new Demo(); // 抽象类不能产生实例对象,所以这样做是错的,实例化对象交给子类
class Test extends Demo {
    function fun1() {
        ...
    }
    function fun2() {
        ...
    }
}
$test = new Test(); // 子类可以实例化对象,因为实现了父类中所有抽象方法

?>

PHP接口

        PHP与大多数面向对象编程语言一样,不支持多重继承。也就是说每个类只能继承一个父类。为了解决这个问题,PHP引入了接口,接口的思想是指定了一个实现了该接口的类必须实现的一系列方法。接口是一种特殊的抽象类,抽象类又是一种特殊的类,所以接口也是一种特殊的类。
        为什么说接口是一种特殊的抽象类呢?如果一个抽象类里面的所有的方法都是抽象方法,那么就换一种声明方法使用“接口”;也就是说接口里面所有的方法必须都是声明为抽象方法,另外接口里面不能声明变量(但可声明常量constant),而且接口里面所有的成员都是public权限的。所以子类在实现的时候也一定要使用public权限实限。
        声明一个类的时候使用的关键字是“class”,而接口一种特殊的类,使用的关键字是“interface”;
        类的定义:  class 类名{ … } ,
        接口的声明:interface 接口名{ …}

<?php
// 定义一个接口使用interface关键字,“One”为接口名称
interface One {
    // 定义一个常量
    const constant = 'constant value';
    // 定义了一个抽象方法”fun1”
    public function fun1(); 
    // 定义了抽象方法”fun2”
    public function fun2();
}

?>

        上例中定义了一个接口“one”,里面声明了两个抽象方法“fun1”和”fun2”,因为接口里面所有的方法都是抽象方法,所以在声明抽象方法的时候就不用像抽象类那样使用“abstract”这个关键字了,默认的已经加上这个关键字,另外在接口里边的”public”这个访问权限也可以去掉,因为默认就是public的,因为接口里所有成员都要是公有的,所在对于接口里面的成员就不能使用“private”的和“protected”的权限了,都要用public或是默认的。另外在接口里面我们也声明了一个常量“constant“, 因为在接口里面不能用变量成员,所以我们要使用 const这个关键字声明。
        可以使用“extends”关键字让一个接口去继承另一个接口:

<?php
// 使用”extends”继承另外一个接口
interface Two extends One {
    function fun3();
    function fun4();
}

?>

        因为接口是一种特殊的抽象类,里面所有的方法都是抽象方法,所以接口也不能产生实例对象; 它也做为一种规范,所有抽象方法需要子类去实现。而定义一接口的子类去实现接口中全部抽象方法使用的关键字是“implements”,而不是前面所说的“extends”;

<?php
// 使用“implements”这个关键字去实现接口中的抽象方法 接口和类之间
class Three implements One {
    function fun1() {
        ...
    }
    function fun2() {
        ...
    }
}
// 实现了全部方法,我们去可以使用子类去实例化对象了
$three = new Three();

?>

        也可以使用抽象类,去实现接口中的部分抽象方法,但要想实例化对象,这个抽象类还要有子类把它所有的抽象方法都实现才行;
        在前面说过,PHP是单继承的,一个类只能有一父类,但是一个类可以实现多个接口,就相当于一个类要遵守多个规范,如,不仅要遵守国家的法律,如果是在学校的话,还要遵守学校的校规一样。

<?php
// 使用implements实现多个接口
class Four implemtns 接口一, 接口二, ... {
    // 必须把所有接口中的方法都要实现才可以实例化对象。
}
?>
PHP中不仅一个类可以实现多个接口,也可以在继承一个类的同时实现多个接口, 一定要先继承类再去实现接口。
<?php
// 使用extends继承一个类,使用implements实现多个接口
class Four extends 类名一 implemtns 接口一, 接口二, ... {
    // 所有接口中的方法都要实现才可以实例化对象
    ...
}

?>

串行化、反串行化
        有时候需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化), 就像现在想把一辆汽车通过轮船运到美国去,因为汽车的体积比较大,可以把汽车拆开成小的部件,然后把这些部件通过轮般运到美国去,到了美国再把这些部件组装回汽车。
有两种情况必须把对象串行化,第一种情况就是把一个对象在网络中传输的时候要将对象串行化,第二种情况就是把对象写入文件或是数据库的时候用到串行化。
        串行化有两个过程,一个是串行化,就是把对象转化为二进制的字符串,使用serialize()函数来串行化一个对象,另一个是反串行化,就是把对象转化的二进制字符串再转化为对象,使用unserialize()函数来反串行化一个对象。
PHP中serialize()函数的参数为对象名,返回值为一个字符串,serialize()返回的字符串含义模糊,一般不会解析这个串来得到对象的信息,只要把返回来的这个字符串传到网络另一端或是保存到文件中即可。
PHP中unserialize()函数来反串行化对象,这个函数的参数即为serialize()函数的返回值,输出当然是重新组织好的对象。

<?
class Person {
    // 下面是人的成员属性
    public $name;  // 人的名字
    public $sex;   // 人的性别
    public $age;   // 人的年龄
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo “我的名字叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
}
$p1 = new Person("张三", "男", 20);
$p1_string = serialize($p1);    // 把一个对象串行化,返一个字符串
echo $p1_string . "<br>";     // 串行化的字符串我们通常不去解析
$p2 = unserialize($p1_string);  // 把一个串行化的字符串反串行化形成对象$p2
$p2->say();

?>

        在PHP5中有两个魔术方法__sleep()方法和__wakeup()方法,在对象串行化的时候,会调用一个__sleep()方法来完成一 些睡前的事情;而在重新醒来,即由二进制串重新组成一个对象的时候,则会自动调用PHP的另一个函数__wakeup(),做一些对象醒来就要做的动作。
        __sleep()函数不接受任何参数, 但返回一个数组,其中包含需要串行化的属性。未被包含的属性将在串行化时被忽略,如果没有__sleep()方法,PHP将保存所有属性。

<?
class Person {
    // 下面是人的成员属性
    var $name;  // 人的名子
    var $sex;   // 人的性别
    var $age;   // 人的年龄
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
    // 指定串行化时把返回的数组中$name和$age值串行化,忽略没在数组中的属性$sex
    function __sleep() {
        $arr = array("name", "age"); // 此时,属性$sex将被删除!!!
        return($arr);
    }
    // 重新生成对象时,并重新赋值$age为40
    function __wakeup() {
        $this->age = 40;
    }
}
$p1 = new Person("张三", "男", 20);
// 把一个对象串行化,返一个字符串,调用了__sleep()方法,忽略没在数组中的属性$sex
$p1_string = serialize($p1);
echo $p1_string . "<br>"; // 串行化的字符串我们通常不去解析 
$p2 = unserialize($p1_string); // 反串行化形成对象$p2重新赋值$age为40
$p2->say();

?>

自动加载

        很多开发者写面向对象的应用程序时,对每个类的定义建立一个 PHP 源文件。一个很大的烦恼是不得不在每个脚本(每个类一个文件)开头写一个长长的包含文件的列表。
        在软件开发的系统中,不可能把所有的类都写在一个PHP文件中,当在一个PHP文件中需要调用另一个文件中声明的类时,就需要通过include把 这个文件引入。不过有的时候,在文件众多的项目中,要一一将所需类的文件都include进来,是一个很让人头疼的事,所以我们能不能在用到什么类的时 候,再把这个类所在的php文件导入呢?这就是我们这里我们要讲的自动加载类。

        在 PHP 5 中,可以定义一个 __autoload()函数,在试图使用尚未被定义的类时自动调用,通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类,__autoload()函数接收的一个参数,就是你想加载的类的类名,所以你做项目时,在组织定义类的文件名时,需要按照一定的规则,最好以类名为中心,也可以加上统一的前缀或后缀形成文件名,比如 xxx_classname.php、classname_xxx.php以及就是classname.php等等。

建立PHP文件,代码如下,在建立libs文件夹,文件夹下建立Test.php文件,DdMysqli.php文件
<?php
function autoload($class){
        $file = __DIR__ . '/libs/' . $class. '.php';
        if(is_file($file)){

                include_once $file;

        }

}

sql_autoload_register('autoload');$

test = new test();

var_dump($test);

$mysqli = new DdMysqli();

var_dump(mysqli);

?>

魔术常量

__LINE__        文件中的当前行号;

__FILE__        文件中的完整路径和文件夹;

__DIR__        文件所在目录;

__FUNCTION__        函数名称;

__CLASS__        类名称;

__TRAIT__        Trait的名称;

__METHOD__        类的方法名;

__NAMESPACE__        当前命名空间的名称;

设计模式

        设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
        使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
        设计模式分为三种类型,共23种。
                创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
                结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
            行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。
        单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
        单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
为什么要使用PHP单例模式
1、php的应用主要在于数据库应用,一个应用中会存在大量的数据库操作,在使用面向对象的方式开发时,如果使用单例模式,可以避免大量的new操作消耗的资源,可以减少数据库连接。
2、如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。

3、在一次页面请求中,便于进行调试,因为所有的代码(例如数据库操作类db)都集中在一个类中,可以在类中设置钩子,输出日志,从而避免到处var_dump、echo。


public        公共属性和方法,它的实例,子类均可以访问以及子类的实例均可以访问,但必须通过实例方式输出const常量    可以直接通过类来访问,可以通过类直接输出
function __construct(){}
用来初始化类的一些属性,具体初始值可以通过不同的子类去设置
function __destruct(){}        用来摧毁对象,释放内存
extends        子类继承父类
parent::        访问父类的常量
self::        自己调用自己的常量        类名::父类常量        外界直接调用类常量
private        定义私有变量和方法        私有方法子类不可以调用,也不可以在类外面访问,类的实例也不能调用,只有所属类内部可以调用和修改
protected        本类和子类可以调用属性和方法,但是实例不可以static静态变量        用法类似于const,但是它每次的变化都会被保存,几个类以及子类和实例中都是同一个引用,不会被复制
final 被final修饰过的类不能再有子类,也就是不能被继承,但是实例可以继续访问它的属性和方法,但是不能被修改
abstract抽象类,不能被实例化,只能作为其他类的父亲使用,并且抽象方法没有方法体,只能通过子类去设置方法体
interface        实现接口类,里面的是一些未实现的方法以及成员变量,一个子类可以继承多个父类,通过关键字
implements来继承,中间用逗号隔开,并且父类中不允许出现其他关键字clone用来克隆一个对象,如果要引用一个对象的话前面要加&或者直接等于;要真正的复制一份需要用克隆关键字,注意:平时每个类的实例对象都是复制一份新的出来
function__clone(){}        对于克隆的对象用的是该方法产生的值        对象是引用还是复制的通过==和===来判断
instanceof用来判断一个实例对象是否是某个类实例化来的,其中包括该类的祖先类
function __set()        当程序试图写入一个不存在或不可见的成员变量时,PHP就会执行__set()方法,该方法含有两个参数,分别表示变量名和变量值
function __get()        当程序试图调用一个未定义或不可见的成员变量时候,可以通过该方法读取变量值,该方法有一个参数,为要调用的变量名
function__call()       当程序调用一个不存在的方法,PHP会调用该方法,该方法有两个参数,第一个为被调用的方法名,第二个是一个数组,包含被调用的方法的所有参数
serialize()用来序列化一个对象
function __sleep()序列化对象时候,对象包含该方法则会先执行该方法,该方法会清除对象,并返回包含该对象中所有变量的数组
unserialize()还原一个被serialize序列化的对象
function__wakeup()回复在序列化中可能丢失的数据库连接
function__toString()输出对象时,将对象转换为字符串
include__once和include__require动态引入类文件
function__autoload()自动实例化需要的类
文章来源: PHP基础知识笔记(面向对象)

人吐槽 人点赞

猜你喜欢

发表评论

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:PHP基础知识笔记(面向对象)