PHP OOP小结

PHP面向对象

面向过程编程:
其基本特征是:
将要完成的任务,分割为若干个步骤:
第1步:做什么。。。
第2步:做什么。。。
.......
最后,做完了,任务完成!



面向对象编程:OOP: Object Oriented  Program(面向对象编程)
其基本特征是:
将要完成的任务,“分派”给不同的“对象”去做;
某对象1:会做什么。。。
某对象2:会做什么。。。
........
程序一旦启动,则各个对象“各司其职”,相互配合就完成了任务。

面向对象中的基本概念
类和对象
对象:  万物皆对象;

类:  任何对象,都可以人为“规定”为某种类型(类别);

class  Person{
var  $name ;
var  $age;
var  $edu;
}
我:
姓名:罗XX, 
年龄40, 
学历:大学;
王亮: 
姓名:王亮
年龄:20;
学历:大学;

class  Teacher{
var  $name ;
var  $age;
var  $edu;
var  $major;        //专业
}


可见:
•   类是描述一类事物的一个总称,是具有相同特征特性的该类事物的一个通用名字(称呼);
•   对象是一个明确的具体的“物体”,是某个类中的一个“实物”(相对来说,类就是一种抽象的泛称)。对象离不开类,或者说,对象一定隶属于某个类——有类才有对象,先有类再有对象。


属性和方法
属性:就是原来的“变量”,只是现在它“隶属于”一个类了,即写在一个类中,就称为属性;
方法:就是原来的“函数”,只是现在它“隶属于”一个类了,即写在一个类中,就称为方法;
注意:属性和方法,已经不能“自由使用”了,而是都要通过这个类或这个类的对象去使用。
使用属性,就把它当做一个“变量”去使用就好了,只是需要该形式:对象->属性名;
使用方法,就把它当做一个“函数”去使用就好了,只是需要该形式:对象->函数名(实参列表...)


创建对象的几种形式
class  C1{
var  $p1 = 1;   //定义一个属性;
}
形式1:
$o1 = new C1(); //通过一个类,去new出一个对象
形式2:
$o2 = new $o1();    //通过一个对象,去new出一个对象——其实是new出来的是旧对象所述类的一个新对象。
形式3:
$s1 = “C1”; //只是一个字符串变量而已;
$o3 = new $s1();    //这就是所谓的“可变类”——无非就是类的名字是一个变量而已。

形式4:
$o4 = new  self();  //self表示“当前类本身”,它只能出现在一个类的方法中。


对象的传值方式:
为什么对于对象,值传递和引用传递,这个情况下,他们似乎没有区别???
这要从对象的数据的存储方式来理解:
$o1 = new C1(); //这里创建一个对象o1,其存储结果


这里,实际上,变量$o1中,存储的数据只是一个“对象编号#1”,这个对象编号,才会去指向对象数据new  C1();  该编号数据,我们不能控制,只是系统内部的分配。

在语法上,对对象变量进行的属性进行操作,其实就是通过该编号来指向对象而操作的。
$o1->p1  =  2;  //此时,就是通过对象编号#1去修改了对象(new  C1() )本身的内部数据.
echo  $o2->p1;  //此时相当于取得变量$o2所包含的编号#1中所指向的对象(new  C1() )的内部数据p1



类中成员
类中成员概述
面向对象编程,是需要通过“对象”去做什么事情(以完成某种任务);
而:
对象总是来源于类;
所以:
面向对象的编程,一切都是从定义类开始;

类中成员分为3大类:
属性:
方法:
常量:
形式上,大致如下:
class  类名 {
常量定义1;
常量定义2;
.......
属性定义1;
属性定义2;
........
方法定义1;
方法定义2;
.......
}
说明:
以上各项,没有顺序问题;习惯上,其实常量放前面,然后是属性,然后是方法;

详细一点,就又分为:
属性:
普通属性;//一般属性,实例属性
静态属性;
方法:
普通方法;//一般方法,实例方法
静态方法;
构造方法;
析构方法;
常量:
类常量
当在一个类中定义一个常量时,该常量就称为“类常量”——本质其实还是常量;
定义形式:
class  类名{
const  常量名 = 常量值;
//不可以使用define()来定义!
}
使用形式:
常量的使用,是通过类名,并使用范围解析符(::)来取用的;
类名::常量名;


普通属性(实例属性):
实例的单词为:instance
实例,其实也叫做“对象”;

普通(实例)属性,就是一个可以在该类实例化出的对象上使用的属性!
定义形式:
class  类名{
var  $属性名  =  初始值;
var  $属性名;      //这个属性没有初始值;
//上述的var 还可以使用public来代替,比如:
public  $属性名  =  初始值;
public  $属性名;       //这个属性没有初始值;
}
使用形式:
是通过该类的对象,来使用普通属性(实例属性):
$对象->属性名;   
因为,属性的本质就是变量,则其就可以当做一个变量来看待和使用,比如:
$v1 = $对象->属性名;
echo  $对象->属性名;
$v2 = $对象->属性名 * 3 + 5; //进行计算

静态属性:
静态属性,本质上也是“变量”,但其有一个特点就是:该变量只隶属于“类”,即:
一个类中的一个静态属性,就只有“一份数据”;
但:
一个类中的一个实例属性,就可以有“多份数据”——每创建一个对象出来,就会有一份数据;
定义形式:
class  类名{
static   $属性名  =  初始值;
static   $属性名;      //这个属性没有初始值;
}
使用形式:
使用类名和范围解析符(::)来对静态属性进行操作:
类名::$静态属性名;     //注意:属性名带$符号
对比1:
常量的使用:类名::常量名;
对比2:
实例属性的使用:对象名->实例属性名; //注意:属性名不带$符号


1,实例属性,是每个对象都可以不一样的数据,也是每个对象都“独自拥有”的数据;
2,静态属性,他不属于任何一个对象,而只属于该类本身,也可以理解为为所有对象所共有的数据;

普通方法(实例方法)
一个类中定义的方法,可以为这个类的所有对象调用的方法。也可以理解为,这个类的所有对象,都各自有自己的一个该方法;

定义形式:
class  类名{
function  方法名(形参1,形参2,.... ){
//方法体。。。
}
}
调用形式:
$对象名->方法名(实参1,实参2,....);

静态方法
一个类中定义的方法,只隶属于这个类本身,而不是隶属于这个类的对象。

定义形式:
class  类名{
static  function  方法名(形参1,形参2,.... ){
//方法体。。。
}
}
调用形式:
类名::方法名(实参1,实参2,....);

构造方法(__construct):
构造方法,是一个特殊的方法:
1,名字是固定的:_ _construct;
2,该方法通常都不要我们自己调用,而是在new一个对象的时候会自动调用。
3,该方法主要的目的是为了在new一个对象的时候,给该对象设置一些“初始值”(初始化工作);
4,构造方法的参数没有规定,通常是根据实际的需要来定义,目的是为了对象属性数据的初始化;


析构方法(__destruct):
说明:
1,析构方法是一个特殊的方法,名字为固定的词:_ _desctruct
2,析构方法是在一个对象被“销毁”的时候会自动被调用的方法——我们无法调用它;
3,析构方法不能带参数(形参),但方法中也可以使用$this这个词,代表“当前对象”;

对象在哪些情况下会被销毁?
1,如果程序结束,所有变量都会被销毁,自然,变量所代表的对象也会被销毁;

对象销毁的顺序,默认情况下,跟其创建的顺序相反;

2,当一个对象没有任何变量“指向”它的时候,即使程序还没有结束,也会被销毁;

  • 继承
基本概念
将一个类A中的特性信息,传递到另一个类B中,此时就称为:
B继承A
A派生出B


class A{

}

class B extends A{
    
}


几个基本概念
•   继承:一个类从另一个已有的类获得其特性,称为继承。
•   派生:从一个已有的类产生一个新的类,称为派生。
•   父类/子类:已有类为父类,新建类为子类。父类又可以称为“基类”,上级类,子类又称为派生类,下级类,
•   单继承:一个类只能从一个上级类继承其特性信息。PHP和大多数面向对象的语言都是单继承模式。C++是多继承。
•   扩展:在子类中再来定义自己的一些新的特有的特性信息(属性,方法和常量)。没有扩展,继承也就没有意义了。
访问控制修饰符
形式:
class  类名{
访问控制修饰符  属性或方法定义;
}

有3个访问修饰符:
•   public公共的:在所有位置都可访问(使用)。
•   protected受保护的:只能再该类内部和该类的子类或父类中访问(使用)。
•   private私有的:只能在该类内部访问(使用)。

他们的作用是:用来“限制”其所修饰的成员的“可访问性”;
可访问性:
就是在代码中使用这样两种语法形式的“有效性”(合法性):
对象->实例属性或方法;
类::静态属性或方法;

访问控制修饰符,需要结合使用该语法形式的所在位置,才能确定是否可访问。

有3个访问位置(范围):
某个类的内部:
某个类的继承类的内部:
某个类的外部:



1,public修饰的成员,哪里都能访问;
2,类的内部,可以访问任何级别的成员;
3,public具有最宽泛的可访问性;private具有最狭小的可访问性;protecte则居中;



parent关键词
parent表示“父母”的意思,在面向对象语法中,代表“父类”
——本质上就是代表父类这个“类”,而不是父类的“对象”;

其使用方式为:
parent::属性或方法;  //通常是静态属性或静态方法,但有时候可能是实例属性或实例方法;





构造方法和析构方法调用上级同类方法的问题
1,如果一个类 有 构造方法,则实例化这个类的时候,就 不会 调用父类的构造方法(如果有);
2,如果一个类没有构造方法,则实例化这个类的时候,就会自动调用父类的构造方法(如果有);



3,如果一个类 有 析构方法,则销毁这个类的时候,就 不会 调用父类的析构方法(如果有);
4,如果一个类没有析构方法,则销毁这个类的时候,就会自动调用父类的析构方法(如果有);
5,如果一个类中有构造方法或析构方法,则就可以去“手动”调用父类的同类方法(如果有);
手动调用的语法形式总是这样:
parent::构造方法或析构方法()

则,第5种情况,parent在构造方法中的一个典型代码(写法):
(在子类的构造方法中,常常需要去调用父类的构造方法,以简化对象的初始化工作。)



覆盖(override):
基本概念
覆盖,又叫“重写”:
含义:
将一个类从父类中继承过来的属性和方法“重新定义”——此时相当于子类不想用父类的该属性或方法,而是想要定义。

覆盖的现实需要:
对于一个父类,或许其属性的现有数据(值),子类觉得不合适,而需要有自己的新的描述;
或许其方法,子类觉得也不合适,需要自己来重新定义该方法中要做到事。
此时就可以使用覆盖。



重写的基本要求:
访问控制权限:
子类覆盖的属性或方法的访问控制权限,不能“低于”父类的被覆盖的属性或方法的访问控制权限:
具体来说:
父类: public      子类:只能是public
父类: protected   子类:可以说protected和public
父类: private 子类:不能覆盖!——既父类的私有成员,不存在被子类覆盖的可能。

方法的参数形式:
子类覆盖父类的同名方法的时候,参数要求跟父类保持一致;
特例:
构造方法重写的时候参数可以不一致

小注意:
虽然父类的私有属性不能被覆盖,但子类却可以定义自己的跟父类同名的属性;
虽然父类的私有方法不能被覆盖,但子类也不能定义自己的同名方法;



最终类
最终类,其实就是一种特殊要求的类:要求该类不允许往下继承下去。

形式:
final  class  类名{
//类的成员定义。。。跟一般类的定义一样!
}

最终方法
最终方法,就是一个不允许下级类去覆盖的方法!!

形式:
class  类名{
final  function  方法名(形参列表...){ 。。。。。 }
}

设计模式
什么叫设计模式?
简单来说,设计模式就是解决某个问题的一般性代码的经验性总结。
类比来说:
它类似之前所学的“算法”:针对某种问题,使用某种特定的语法逻辑就可以完成该任务。

工厂模式
所谓工厂模式,就是这样一个类(就是所谓的工厂类):
它可以根据“传递”给他的类名,而去生产出对应的类的对象。

class A{}
class B{}

class FactoryClass{
    static function GetObject($className){
        $obj = new $className();
        return $obj;
    }
}

$obj1 = FactoryClass::GetObject("A");
$obj2 = FactoryClass::GetObject("B");
$obj3 = FactoryClass::GetObject("A");



单例模式:
例,就是实例(Instance),其实就是对象(object)
单例:就是一个对象;
单例模式:就是设计这样一个类,这个类只能“创造”出它的一个对象(实例);


class Singleton{
    private function __construct(){
    
    }
    
    static private $instance = null;
    static function ShareInstance(){
        if(!isset(self::$instance)){
            $obj = new self();
            self::$instance = $obj;
            return $obj;
        }
        
        return self::$instance;
    }
}

  • 设计一个MySQL数据库操作类
设计目标:
1,该类一实例化,就可以自动连接上mysql数据库;
2,该类可以单独去设定要使用的连接编码(set  names  XXX)
3,该类可以单独去设定要使用的数据库(use  XXX);
4,可以主动关闭连接;
上述设计目录,大致上相当于如下几行代码:
$link  =  mysql_connect(“localhost”, “root”, “123”);
mysql_query(“set names XXX”);
mysql_query(“use  XXX”);
然后,后面就可以执行各种sql语句来:
$r1 = mysql_query(“insert into ....”);
$r2 = mysql_query(“delete from .....”)
$r3 = mysql_query(“select * from ....”);





class MySQLDB{
    publick $link = null;
    function __construct($host,$port,$username,$password,$charset,$dbname){
        $this->link = @mysql_connect("$host:$port","$username","$password") or die("connect failure!");
        
        mysql_query("set names $charset");
        mysql_query("use $dbname");
    }
    
    function setCharset($charset){
        mysql_query("set names $charset")
    }
    
    function selectDB($dbname){
        mysql_query("use $dbname");
    }
    
    function closeDB(){
        mysql_close($this->link)
    }
    
}

//使用

$host = "localhost";
$port = 3306;
$username = "root";
$password = "aaa"
$charset = "utf8";
$dbname = "info";

$db = new MySQLDB($host,$port,$username,$password,$charset,$dbname);

$result = mysql_query("select * from tab_int");

$db->setCharset("gbk");


$db->closeDB();

  • 抽象类,抽象方法
抽象类:
是一个不能实例化的类;

定义形式:
abstract  class  类名{}

为什么需要抽象类:
它是为了技术管理而设计!


抽象方法:
是一个只有方法头,没有方法体的方法定义形式;

定义形式:
abstract  function  方法名( 形参1,形参2,.... );    //注意,这里必须有分号;

为什么需要抽象方法:
它也是为了技术管理而设计:要求下级类需要去实现这个方法的“具体做法”;



抽象类和抽象方法的细节
1,一个抽象方法,必须在抽象类中;
2,反过来,抽象类中可以没有抽象方法——虽然不常见;
3,可见:抽象方法是为了规定下级类中“必须”要具体去完整某个工作(任务);
4,下级类中继承了上级类的抽象方法,则要么去“实现该方法的具体内容”,要么自己也作为抽象类(即其继承的抽象方法仍然是抽象的);
5,子类实现父类的抽象方法的时候,其形参也应该跟父类保持一致,其访问权限也不能更小;
——其原因其实这是“重写现象”,自然应该遵循重写的要求;


重载技术overloading
重载的基本概念
重载在“通常面向对象语言”中的含义:
是指,在一个类(对象)中,有多个名字相同但形参不同的方法的现象;
类似这样:
class   C{
function  f1(){。。。}
function  f1($p1){。。。}
function  f1($p1,  $p2  ){。。。}
}
$c1 = new C();
$c1->f1();
$c1->f1(2);
$c1->f1(3,4);


重载在“php语言”中的含义:
是指,当对一个对象或类使用其未定义的属性或方法的时候,其中的一些“处理机制”;
比如:
class  A{
public  $p1 = 1;
}
$a1 = new A();
echo   $a1->p1;     //1;
echo   $a1->p2;     //出错,未定义的属性!
则:php中的重载技术,就是来应对上述“出错”的情况,使代码不出错,而且还能“优雅处理”;

class A{
    public $p = 1;
}

$a = new A();

echo $a->p; //1
echo $a->p2; //报错


//处理

class A{
    public $p = 1;
    
    function __get($pro_name){
        echo "调用了未定义字段"
    }
}

$a = new A();

echo $a->p; //1
echo $a->p2; //不报错,直接调用方法->调用了未定义字段


属性重载
就是对一个对象的不存在的属性进行使用的时候,这个类中预先设定好的应对办法(处理机制);

属性,本质,就是变量,其只有4个操作:
取值:
当对一个对象的不存在的属性进行“取值”的时候,就会自动调用内部方法:__GET()
赋值:
当对一个对象的不存在的属性进行“赋值”的时候,就会自动调用内部方法:__SET()
判断(isset):
当对一个对象的不存在的属性进行isset()判断的时候,就会自动调用内部方法:__isset()
销毁(unset):
当对一个对象的不存在的属性进行unset()销毁的时候,就会自动调用内部方法:__unset()

以上,4个方法,被称为“魔术方法”;

__GET($属性名):
在对一个对象的不存储的属性进行“取值”的时候,会自动调用的方法;
我们其实是可以使用该方法来对这种“意外”情况进行某种特别的处理。
其中,该方法可以带一个形参,表示这个要对之取值的不存在的属性名(字符串);



__SET($属性名,值):
当对一个对象的不存在的属性进行“赋值”的时候,就会自动调用这个内部的魔术方法;
它有2个形参,分别代表要对不存在的属性进行赋值的时候的“属性名”和“属性值”;

这个方法,结合__GET方法,往往可以使我们定义的类,就有一种“可方便扩展属性”的特性。
即:类(或对象)的属性,可以更为方便自由,



class A{
    protected $prop_list = array();
    
    function __set($p,$v){
        $this->prop_list[$p] = $v;
    }
    
    function __get($p){
        return $this->prop_list[$p];
    }
}



__ISSET($属性名):
当对一个对象的不存在的属性进行isset()判断的时候,就会自动调用内部方法:__isset();
用法:
$v1 = isset($对象 -> 不存在的属性); //  此时就会调用这个对象的所属类中的魔术方法:__isset()

function __isset($prop){
    $v = isset($this->prop_list[$prop]);
    return $v;
}


__UNSET($属性名):

当对一个对象的不存在的属性进行unset()销毁操作的时候,就会自动调用内部方法:__unset()

function __unset($prop){
    unset($this->prop_list[$prop]);
}



方法重载
当对一个对象的不存在的实例方法进行“调用”的时候,会自动调用类中的__call()这个魔术方法;

当对一个类的不存在的静态方法进行“调用”的时候,会自动调用类中的__callstatic()这个静态魔术方法;


class A{
    function __call($method,$args){
        echo "__call被调用了!"
    }
}


利用php的重载技术,实现通常的“方法重载”


  • 接口 interface
什么是接口?
先看抽象类:
abstract  class  类名  {
属性1;
属性2;
.....
非抽象方法1;
非抽象方法2;
......
抽象方法1;
抽象方法2;
......
}  
设想,将上述抽象类中“实在的成员”,删除,即删除那些非抽象的成员。则,自然该抽象类中,就只有抽象方法;
abstract  class  类名  {
抽象方法1;
抽象方法2;
......
}  
由此,可以理解为:这个抽象类,“太抽象了”,几乎自己什么都没做,就光让别人做什么。

那么:

接口就是这样一个“天然不实在”的家伙:
接口,就是规定,里面只能放“抽象方法”和“常量”的一种类似类的语法结构;
——可见,接口就是“比抽象类更抽象的”一种语法结构。

接口(interface)定义形式:
interface  接口名{
常量1;
常量2;
.....
抽象方法1;
抽象方法2;
.....
}
说明:
1,可见,接口中,只有常量(接口常量)和抽象方法两种成员;
2,接口常量的使用形式为: 接口名称::常量名称;
3,接口中的抽象方法,不要使用abstract修饰,也不需要使用访问控制修饰符,因为其天然就是public



为什么需要接口?
面向对象编程思想是对“现实世界”的描述(模拟)!
现实世界往往都都是多继承的;
但:
出于降低类跟类之间关系的复杂度的考虑,就将语言设计为单继承的;
但这样,就无法表达出现实世界的多继承特性;
则:
接口就是对没有多继承的类之间关系的一个补充;

因为:接口可以实现“多继承”——但此时不称为继承而已,而是称为“实现”;
即:
接口1  -->> 类1;
就称为:类1实现了接口1;
其本质,其实就是类1中,有了接口1中“特征信息”;



使用形式:
形式为:
class  类名  implements  接口名1, 接口名2, ....{    
//类的定义。
}
这里,叫做,类实现了接口。



其中,接口跟接口之间,也可以继承,跟类之间的继承:
interface  接口1  extends  接口2{
//接口的成员定义;。。。。
}



进一步完善mysqldb工具类:
完善分2个方面:
1,现有已经完成的功能,做优化处理;
2,添加更多的功能,要求继续实现如下功能:
2.1:用该类的对象可以执行任意的增删改语句,并返回布尔值;
2.2:用该类的对象可以执行返回一行数据的“查询语句”:结果是一个一维数组,类似这样:
array( ‘id’=>3,  ‘name’=>’张三’,  ‘age’ => 18,  ‘edu’=>’大学’ );
2.3:用该类的对象可以执行返回多行数据的“查询语句”:结果是一个二维数组,类似这样:
array(
0=>array( ‘id’=>3,  ‘name’=>’张三’,  ‘age’ => 18,  ‘edu’=>’大学’ ),
1=>array( ‘id’=>4,  ‘name’=>’张四’,  ‘age’ => 14,  ‘edu’=>’中学’ ),
2=>array( ‘id’=>7,  ‘name’=>’张七’,  ‘age’ => 17,  ‘edu’=>’小学’ )
)
2.4:用该类的对象可以执行返回一个数据的“查询语句”:结果是一个数据值,其sql语句常常类似这样:  select  name  from  Users  where id = 1;  或: select  count(*) as c  from  表名;

  • 类的自动加载
含义:
当某行代码需要一个类的时候,php的内部机制可以做到“自动加载该类文件”,以满足该行需要一个类的这种需求。

什么时候需要一个类?
1,new一个对象的时候;
2,使用一个类的静态方法的时候;
3,定义一个类(B)并以另一个类(A)作为父类的时候;



function __autoload($name){
    require_once './'.$name.'.class.php'
}

$config = array(
    "host"=>"localhost",
    "port"=>3306,
    "username"=>"root",
    "password"=>"aaa",
    "charset"=>"utf8",
    "dbname"=>"db123"
    );
    
    $db = MySQLDB::ShareInstance($config);

    条件和要求
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 ){
//.......
}
.............

这样,系统就会一次调用这些自动加载函数去加载所需要的类,直到加载成功!



spl_autoload_register("autoload1");
spl_autoload_register("autoload2");

function autoload1($class_name){
    $file = './class/'.$class_name.".class.php";
    if(file_exists($file)){
        include_once $file;
    }
}

function autoload2($class_name){
        $file = './lib/'.$class_name.".class.php";
    if(file_exists($file)){
        include_once $file;
    }
}



对象的复制(克隆)
$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,  这里能够遍历出来的属性,只能是在该范围中的“可访问属性”(就是要考虑访问控制权限)
}



将一个对象的所有属性都遍历出来

class A{
    public $p1 = 1;
    protected $p2 = 2;
    private $p3 = 3;
    static $p4 = 4;
    
    function showAllProperties(){
        foreach($this as $key=>$vlue){
            ...
        }
    }
}




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()

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

注意:
如果没有定义该方法,则对象无法当做字符串来使用!

__invoke()魔术方法:
将对象当作函数来使用的时候,会自动调用该方法。通常不推荐这么做。
class  A{
function  __invoke(){
echo “
我是一个对象呀,你别当我是一个函数来随便调用!”; } } $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它就比较死板,只代表这个单词本身所在位置的所在类。 面向对象编程思想的3个特征: 封装: 无非是一个大的指向思想,目的是为了将一个类设计得更为健壮! 其基本做法是: 尽可能地将一个类的成员私有化,只开放那些必不可少的对外的属性或方法,能private的就不要protected。能protected就不要public 继承: 是面向对象的基本思想和基本做法。 继承是代码重用的一种重要机制。 多态: 多态,就是“多种形态”,其实指的是,现实世界的“丰富多彩的表现形式”,比如: 人在吃饭; 猪在吃食; 鱼在进食; 小鸡啄米; 。。。。 他们都是“吃”这个行为! 在实际代码(应用)中,多态常常有两种表现形式: 1, 不同对象,使用相同的方法,会表现为不同的结果! 2, 同一个对象,使用相同的方法,也可能会表现为不同的结果——这其实是“方法重载现象”

你可能感兴趣的:(PHP OOP小结)