面向对象(四)

前言:这个章节主要分享一些高级的PHP面向对象的知识

(一) 两种常见的设计模式(单例和工厂模式)

  引言:在PHP中,存在两种常见的设计模式,一个是单例模式,另一个是工厂模式,这两中设计模式,并不是固定的PHP语法,而是广大的开发工作者在长期的开发工作中总结出来的开发经验。

  1.单例模式

<?php
//单例模式实现的目标效果是: 无论我们实例化多少次,都只能得到唯一的一个对象(空间)。
class A{
    private static $_obj;//定义了一个  静态的  私有的  属性

    //将构造方法私有化,使得无法在类的外部使用new关键字实例化这个类的对象
    private function __construct(){ 

    }

    private function __clone(){ 
        
    }

    //定义一个共有的  静态的  方法single
    public static function single(){ 
        
        //判断$_obj静态私有属性是否保存了一个本类的对象
        if( empty(self::$_obj) ){//如果$_obj为空,则表示之前没有创建过本类的对象
            self::$_obj = new self;
        }
        return self::$_obj;
    }
}

  2.工厂模式

<?php

class Factory{

    public static function produce($className){ 
        
        if( $className=='A' ){
        
            include './A.class.php';

        }elseif( $className=='B' ){
        
            include './B.class.php';
        }

        $obj = new $className;
        return $obj;
    }
}

$a1 = Factory::produce('A');
var_dump( $a1 ); echo '<hr/>';
$b1 = Factory::produce('B');
var_dump( $b1 ); 

  (二) 对象遍历

   引言:对象和数组本质上同属于复合数据类型,我们可以在程序中可以对数组进行遍历。

   1.默认的对象遍历

<?php

class A{
    
    public $name='zhangsan';
    public $age=12;
    public $height=1.8;
}

$a1 = new A;
var_dump( $a1 ); echo '<hr/>';echo '<hr/>';

//实现使用foreach对对象进行遍历
foreach( $a1 as $k=>$v ){ 
    
    echo '$k:'; 
    var_dump( $k ); echo '<br/>';
    echo '$v:'; 
    var_dump( $v ); echo '<hr/>';
}
//小结:默认的对象遍历,就是逐个的获得对象中的属性(属性名和属性值);

  2.自定义对象遍历

  实现自定义对象遍历的前提:需要实现PHP预定义接口"Iterator"

  自定义对象遍历的概念:当遍历一个对象时,PHP自动按顺序执行预定义接口Iterator中实现的五个方法

<?php


class A implements Iterator{

    public $count=0;

    public function current(){ 
        echo 'current<br/>'; 
    }

    public function key(){ 
        echo 'key<br/>'; 
    }

    public function next(){ 
        echo 'next<br/>'; 
    }

    public function rewind(){ 
        echo 'rewind<br/>'; 
    }

    public function valid(){ 
        
        $this->count++;

        if( $this->count<4 ){
            echo 'valid<br/>';
            return true;
        }else{
            return false;
        }
    }
}

$a1 = new A;
var_dump( $a1 ); echo '<hr/>';

foreach( $a1 as $k=>$v ){ 
    
    
}

小结:
  1. 第一次将会按照 rewind->valid->current->key->next这个顺序执行五个被实现的方法;

  2. 第二次以后会按照 valid->current->key->next这个顺序循环执行4个被实现的方法;

  (三) 对象序列化

  在PHP中,如果我们直接将(PHP八种数据类型)数据写入文件中,那么,除了字符串数据外,其他的数据都将会失真

  概念:对象的序列化就是通过serialize函数将某个对象转换成一个具有固定信息格式的字符串。涉及的函数:serialize(对象) 将对象进行序列化

<?php

class DirTool{
    public $path;
    public $resource;
    
    public function __construct(){
        $this->path = './dir';
        $this->resource = opendir($this->path);
    }
}

$d = new DirTool;
var_dump( $d ); echo '<hr/>';

//将$d对象进行序列化,获得序列化之后的字符串结果
$str = serialize($d);
var_dump( $str ); 

小结:

  1. 经过序列化之后的对象,变成了一个具有一定格式的字符串。

  2. 资源类型的数据即使序列化之后也会失真,所以一般我们在对对象进行序列化的时候,会把资源类型的数据排除在外

  2.__sleep魔术方法

<?php

class DirTool{
    public $path;
    public $resource;
    
    public function __construct(){
        $this->path = './dir';
        $this->resource = opendir($this->path);
    }

    //__sleep魔术方法   当基于该类的对象被序列化的时候,__sleep魔术方法将被触发执行
    public function __sleep(){ 
        //echo 100; 
        return ['path'];//不在数组中的属性名,将会被排除在序列化操作之外
    }
}

$d = new DirTool;
var_dump( $d ); echo '<hr/>';

//将$d对象进行序列化,获得序列化之后的字符串结果
$str = serialize($d);
var_dump( $str ); 

小结

  1. PHP不负责定义__sleep魔术方法,只负责调用该魔术方法;

  2. 调用该魔术方法的时机是:当使用serialize函数序列化一个对象时,该类中的__sleep魔术方法将会被触发自动执行;

  3. 在__sleep魔术方法中,可以同return语句指定乃个属性应该参与到序列化的过程中来,不在数组中的属性都将被排除在序列化的过程之外;

 

  (四) 对象的反序列化

  概念:对象的反序列化就是通过unserialize函数将某个对象序列化后的字符串还原回原来的对象。涉及的函数:unserialize(序列化后的字符串) 将对象进行反序列化

<?php

$str = 'O:7:"DirTool":2:{s:4:"path";s:5:"./dir";s:8:"resource";i:0;}';
//将序列化后的字符串进行反序列化,还原回对象
$obj = unserialize($str);

var_dump( $obj ); 

小结:我们从效果上看,虽然反序列化回了对象,但是找错了所属的类,这是因为在反序列化的过程中,需要有一个条件,那就是,必须存在这个对象的原始类的定义,即要在序列化的同一个php文件中进行

<?php

class DirTool{
    public $path;
    public $resource;
    
    public function __construct(){
        $this->path = './dir';
        $this->resource = opendir($this->path);
    }
}

$str = 'O:7:"DirTool":2:{s:4:"path";s:5:"./dir";s:8:"resource";i:0;}';
//将序列化后的字符串进行反序列化,还原回对象
$obj = unserialize($str);

var_dump( $obj ); 

小结:

  1. 我们可以使用unserialize函数对序列化后的字符串结果进行反序列化;

  2. 反序列化有一个前提,在反序列化的过程中,必须存在该对象的原始类的定义,否则将会把还原的对象归到一个系统类__PHP_Incomplete_Class下;

<?php

class DirTool{
    public $path;
    public $resource;
    
    public function __construct(){
        $this->path = './dir';
        $this->resource = opendir($this->path);
    }

    //__wakeup魔术方法
    public function __wakeup(){ 
        $this->resource = opendir($this->path);
    }
}

//$str = 'O:7:"DirTool":2:{s:4:"path";s:5:"./dir";s:8:"resource";i:0;}';
$str = 'O:7:"DirTool":1:{s:4:"path";s:5:"./dir";}';
var_dump(unserialize($str));

小结

  1. 我们在__wakeup魔术方法中所作的操作,其实就是将之前排除的属性重新进行赋值操作;

  2. PHP不负责定义__wakeup魔术方法,只负责调用该魔术方法;

  3. 调用该魔术方法的时机是:当使用unserialize函数反序列化一个字符串时,该类中的__wakeup魔术方法将会被触发自动执行;

 

  (五) 命名空间

  

#关键字为namespace
namespace  空间名; 

注意事项:命名空间首次定义之前不能有任何PHP非注释代码

  命名空间的使用

<?php

namespace first;

function f1(){ 
    echo 100; 
}

namespace second;

function f1($v1){ 
    echo 200; 
}

f1();//就近原则,不限定名称访问
\first\f1();// 限定命名空间的访问
echo '嘿嘿嘿嘿,能看到我么';

  

  命名空间的引入

//空间的引入,接上一个方法
use \first;
f1();

小结 :

  1.命名空间都是在全局空间下的

  2.命名空间如果需要用到另外的空间需要用use引入才可以使用

猜你喜欢

转载自www.cnblogs.com/learningPHP-students2018/p/10201425.html