Heim  >  Artikel  >  Backend-Entwicklung  >  PHP-Grundlagen-Tutorial 13: Reflexion und Objektserialisierung

PHP-Grundlagen-Tutorial 13: Reflexion und Objektserialisierung

黄舟
黄舟Original
2017-03-01 10:12:491471Durchsuche

Inhalt in diesem Abschnitt erklärt

  • Klon von Objekten

  • Durchlauf von Objekten

  • Serialisierung und Deserialisierung von Objekten

  • Verwendung integrierter Standardklassen

  • Merkmale Verwendung

  • Verwandte Funktionen von Klassen und Objekten

  • PHP-Reflexionsmechanismus

Vorwort

Die Objektorientierung von PHP ist ein wichtiger Wissenspunkt, und seine Ideen ziehen sich durch den gesamten Prozess unserer Entwicklung. Es gibt einige Wissenspunkte in der Objektorientierung, die wir verstehen müssen, wie z. B. die Eigenschaften des Objektklonens und der Objektdurchquerung sowie der Objektserialisierung und -deserialisierung. Wenn Sie ein PHP-Framework schreiben möchten, müssen Sie auch über PHP nachdenken .

Klon eines Objekts

Wenn wir ein Objekt erstellen, wird ein Speicherplatz im Speicher zugewiesen, und der Objektname verweist auf diesen Speicherplatz. Wir haben über die Zuweisung gesprochen Wenn ein Objekt die darin enthaltenen Daten ändert, ändern sich auch die Daten des anderen Objekts entsprechend, da die Zuweisung dem Zuweisen einer Kopie der Objektkennung entspricht, das Klonen jedoch nicht.

<?php

class Person{
    public $name;
    public $age;
    public $sex;
    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }

    public function getName(){
        return $this -> name;
    }

    public function getAge(){
        return $this -> age;
    }

    public function getSex(){
        return $this -> sex;
    }
}

$a = new Person(&#39;宋江&#39;,&#39;45&#39;,&#39;男&#39;);
echo &#39;<pre class="brush:php;toolbar:false">&#39;;

$b = clone $a;
$b -> name = &#39;武松&#39;;
var_dump($a);
var_dump($b);

Ergebnis

Die Syntax des Objektklonens:

$新对象 = clone $就对象;

Wie aus den obigen Ergebnissen ersichtlich ist, an Objekt Datenänderungen wirken sich nicht auf die Daten eines anderen Objekts aus. Durch das Klonen von Objekten wird ein völlig neues Objekt erstellt. Es kann wie folgt verstanden werden:

Unter den magischen Methoden von PHP gibt es eine magische Methode im Zusammenhang mit dem PHP-Klonen, __clone() Wenn der Kopiervorgang abgeschlossen ist Es ist in der Klasse definiert. Wenn die magische Methode __clone() verwendet wird, ruft das neu erstellte oder kopierte Objekt diese __clone()-Methode auf. In dieser Methode können Sie bei Bedarf einige Änderungen an den Attributen vornehmen.

Wenn Sie nicht möchten, dass ein Objekt geklont wird, können Sie die magische Methode __clone() intern als privat definieren. Wenn Sie zu diesem Zeitpunkt klonen, werden Sie zur Eingabe von

Call to private Peoson::__clone() from context &#39;&#39;

Objekt Das Durchlaufen von

Objekten kann auch als Durchlaufen und Anzeigen der Attribute und Werte eines Objekts verstanden werden. Der foreach-Schleifenkörper wird zum Durchlaufen verwendet. Grundlegende Syntax:

foreach(对象名 as $key => $val){
    //$key是属性名,$val是属性值
}

<?php

    class Person{
    public $name;
    public $age;
    private $sex;
    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }
}

$person = new Person(&#39;孙悟空&#39;,256,&#39;男&#39;);

foreach ($person as $key => $value) {
    echo $key . &#39; = &#39; . $value . &#39;<br>&#39;;
}
.......结果........
name = 孙悟空
age = 256
Beim Durchlaufen von Objekten können nur die Eigenschaften durchlaufen werden, deren Modifikatoren öffentlich und privat sind. Auf sie kann nicht außerhalb der Klasse zugegriffen werden, daher wird das Objekt außerhalb der Klasse durchlaufen Beim Durchlaufen können die mit diesen beiden Modifikatoren geänderten Attribute nicht abgerufen werden, genau wie das Geschlechtsattribut im obigen Code.

Serialisierung und Deserialisierung von Objekten

Wenn das Programm in PHP die Ausführung einer Datei beendet, wird der Speicher automatisch freigegeben. Die in der Datei erstellten Objekte und Variablen usw. verschwinden. Wenn wir ein Objekt in einer Datei erstellen und dieses Objekt in einem anderen Objekt verwenden möchten, können wir die Serialisierung (serialize()) und die Deserialisierung (unserialize()) des Objekts verwenden.

Die Serialisierung und Deserialisierung von Objekten kann als Konvertierung des Objekts in eine Zeichenfolge und Speichern in einer Datei verstanden werden. Wenn Sie das Objekt verwenden, deserialisieren Sie die Datei, um das Objekt zu erhalten Datei ein.

Schema:

Eine.php-Datei, ein Objekt erstellen und speichern:

<?php

    class Person{
    public $name;
    public $age;
    private $sex;
    public function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }
}

$person = new Person(&#39;孙悟空&#39;,256,&#39;男&#39;);
//使用file_put_contents()函数把将一个字符串写入文件 
file_put_contents(&#39;D:person.txt&#39;, serialize($person));
Der obige Code file_put_contents() Funktion Schreibt eine Zeichenfolge in eine Datei.

Nachdem Sie den obigen Code ausgeführt haben, können Sie sehen, dass sich auf dem Laufwerk D eine Datei „person.txt“ befindet, die ein in eine Zeichenfolge konvertiertes Objekt enthält.

b.php-Datei, verwenden Sie das Objekt person in der a.php-Datei

<?php

    class Person{
        public $name;
        public $age;
        private $sex;
        public function __construct($name,$age,$sex){
            $this -> name = $name;
            $this -> age = $age;
            $this -> sex = $sex;
        }
    }
    //通过file_get_contents这个方法把一个文件读取到字符串。
    $str = file_get_contents(&#39;D:person.txt&#39;);
    //进行反序列化。
    $person = unserialize($str);
    echo &#39;<pre class="brush:php;toolbar:false">&#39;;
    var_dump($person);
    ......结果......
    object(Person)#1 (3) {
      ["name"]=>
      string(9) "孙悟空"
      ["age"]=>
      int(256)
      ["sex":"Person":private]=>
      string(3) "男"
    }
in b.php über die Methode file_get_contents() Lesen Eine Datei in eine Zeichenfolge umwandeln und diese dann über unserialize() deserialisieren. Das durch die Deserialisierung erhaltene Objekt ist jedoch kein Personenobjekt. Fügen Sie daher die Deklaration der Personenklasse in die Datei ein, kopieren Sie sie und konvertieren Sie sie automatisch in ein Personenobjekt.

Serialisierung und Deserialisierung von Objekten ermöglichen die gemeinsame Nutzung eines Objekts durch mehrere Dateien.

In PHP integrierte Standardklassen

Manchmal möchten wir einige Daten als Attribute von Objekten speichern und gleichzeitig keine Klasse definieren , können wir die Verwendung von PHP in Betracht ziehen. Die Standardklasse stdClass ist eine vom System bereitgestellte virtuelle Klasse und kann direkt verwendet werden, ohne dass wir sie definieren müssen.

<?php

    $person = new StdClass();
    $person -> name = &#39;孙悟空&#39;;
    $person -> age = 524;
    $person -> sex = &#39;男&#39;;
    echo &#39;<pre class="brush:php;toolbar:false">&#39;;
    var_dump($person);
    ......结果......
    object(stdClass)#1 (3) {
      ["name"]=>
      string(9) "孙悟空"
      ["age"]=>
      int(524)
      ["sex"]=>
      string(3) "男"
    }
Aus dem obigen Code können wir ersehen, dass die stdClass-Klasse verwendet werden kann, ohne sie zu definieren.

Verwendung von Traits

Traits ist ein Code-Wiederverwendungsmechanismus, der für Sprachen mit einfacher Vererbung wie PHP vorbereitet ist. Merkmale sollen die Einschränkungen von Sprachen mit einfacher Vererbung verringern und Entwicklern die freie Wiederverwendung von Methodensätzen in unabhängigen Klassen innerhalb verschiedener Hierarchien ermöglichen. Es kann als Definition eines Codeblocks in Merkmalen verstanden werden, der in verschiedenen Klassen verwendet werden kann.

Illustration:


traits使用语法:

trait 自定义名称{
    //额外定义的代码
}
在类中使用格式
use 自定义的名称;

代码:

<?php
    //使用trait,自定义名称
    trait my_code{
        public function minus($num1,$num2){
            return $num1 - $num2;
        }
    }

    class A{
        public function plus($num1,$num2){
            return $num1 + $num2;
        }
    }

    class B extends A{
        //使用trait定义的代码块
        use my_code;
    }

    class C extends A{
        use my_code;
    }

    class D extends A{

    }

    $b = new B();
    $c = new C();
    $d = new D();
    echo $b -> plus(1,2);
    echo &#39;<br>&#39;;
    echo $b -> minus(2,1);
    echo &#39;<br>&#39;;

    echo $d -> plus(1,2);
    echo &#39;<br>&#39;;
    echo $d -> minus(2,1);
    ......结果......
    3
    1
    3
    Fatal error: Call to undefined method D::minus() in D:\mywamp\Apache24\htdocs\zendstudio\yunsuanfu\staits.php on line 36

在上面代码中类D没有使用trait代码,所以在使用minus方法时,出现错误。

当我们在trait中写的函数和父类的函数一样时,以trait代码为准,即trait代码的优先级高于继承的类。

类与对象相关函数

在PHP中系统提供了一系列的函数来判断类和对象的。从帮助文档中可以看到好多函数:

在这里我们只对里面的几个函数进行了解。

<?php

    class Person{
        public $name;
        public $age;
        private $sex;
        public function __construct($name,$age,$sex){
            $this -> name = $name;
            $this -> age = $age;
            $this -> sex = $sex;
        }

        public function showInfo(){
            echo &#39;名字是:&#39; . $this -> name . &#39;,年龄是:&#39; . $this -> age . &#39;,性别是:&#39; . $this -> sex . &#39;<br>&#39;; 
        }
    }

    //判断是否创建了对象,没有创建返回true,创建返回false。
    if(class_exists(&#39;Person&#39;)){
        $person = new Person(&#39;唐僧&#39;,25,&#39;男&#39;);
        //返回对象的类名
        echo &#39;类名是: &#39; . get_class($person) . &#39;<br>&#39;;
        //判断方法是否存在。
        if(method_exists($person, &#39;showInfo&#39;)){
            $person -> showInfo();
        }else{
            echo &#39;该方法不存在&#39;;
        }
        //判断属性是否存在
        if(property_exists($person,&#39;name&#39;)){
            echo $person -> name;
        }else{
            echo &#39;属性不存在&#39;;
        }
    }else{
        echo &#39;类不存在&#39;;
    }
    ......结果......
    类名是: Person
    名字是:唐僧,年龄是:25,性别是:男
    唐僧

使用类和对象函数,可以保证我们代码的完整性,对出错信息进行及时的捕获输出。

PHP反射机制

在很多编程语言中都有反射这种概念,反射简单理解就是通过类,获取里面的属性,方法,甚至注释也可以,不管属性和方法的访问修饰符是什么类型都可以获取到。

在PHP 5中具有完整的反射API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。而我们在开发中一般是使用不到反射的,但是在某些情况下使用反射可以更好的处理问题,比如我们需要我们写框架底层,扩展功能,管理大量的未知类。

定义一个类,通过反射创建对象和调用里面的方法:

<?php

    class Dog{

        public $name;
        protected $age;
        private $food;

        public function __construct($name, $age, $food){

            $this->name = $name;
            $this->age = $age;
            $this->food = $food;
        }

        public function cry($sound){

            echo &#39;<br> &#39; . $this->name . &#39; 叫声是.&#39; . $sound;
        }

    }

    //使用反射完成对象的创建和方法调用
    //1. 创建一个反射对象
    $reflect_obj = new ReflectionClass(&#39;Dog&#39;);

    //2. 通过反射对象创建Dog对象实例
    $dog = $reflect_obj->newInstance(&#39;大黄狗&#39;, 4, &#39;排骨&#39;);
    echo &#39;<pre class="brush:php;toolbar:false">&#39;;
    var_dump($dog);

    //3. 调用方法-使用代理方式.
    $reflect_method_cry = $reflect_obj->getMethod(&#39;cry&#39;);
    echo &#39;<pre class="brush:php;toolbar:false">&#39;;
    var_dump($reflect_method_cry);
    //4. 代理调用cry
    $reflect_method_cry->invoke($dog, &#39;汪汪&#39;);

结果:


在上面代码中,我们通过new创建了一个反射的对象,在反射对象里面通过newInstance()方法得到类的对象。获取里面的方法可以使用反射对象的getMethod()方法,返回来的是一个方法对象ReflectionMethod类,通过里面的invoke()方法执行该方法。这里只是基本的介绍,可以查找帮助文档了解更多的反射对象和方法。

反射实现TP控制器调度

需求:

有一个类IndexAction,其中的方法和访问控制修饰符是不确定的,
1. 如果index 方法是public,可以执行 _before_index.
2. 如果存在_before_index 方法,并且是public的,执行该方法
3. 执行test方法
4. 再判断有没有_after_index方法,并且是public的,执行该方法

代码:

<?php

    class IndexAction{
        public function index(){
            echo &#39;index<br>&#39;;
        }

        public function _before_index(){
            echo &#39;_before_index方法执行 <br>&#39;;
        }

        public function test($data){
            echo &#39;data : &#39;  . $data . &#39;<br>&#39;;
        }

        public  function _after_index(){
            echo &#39;_after_index方法执行<br>&#39;;
        }
    }

    if(class_exists(&#39;IndexAction&#39;)){
        //创建对象
        $reflectionClass = new ReflectionClass(&#39;IndexAction&#39;);
        //判断index是否存在
        if($reflectionClass -> hasMethod(&#39;index&#39;)){

            //获取index方法对象
            $reflec_index_method = $reflectionClass -> getMethod(&#39;index&#39;);
            //判断修饰符是否是public
            if($reflec_index_method -> isPublic()){
                //判断是否有_before_index方法
                if($reflectionClass -> hasMethod(&#39;_before_index&#39;)){
                    $reflec_before_method = $reflectionClass -> getMethod(&#39;_before_index&#39;);
                    //判断是否是public
                    if($reflec_before_method -> isPublic()){
                        $reflec_before_method -> invoke($reflectionClass -> newInstance());
                        //调用test()方法
                        $reflectionClass -> getMethod(&#39;test&#39;) -> invoke($reflectionClass -> newInstance(),&#39;这是test的数据&#39;);
                        //判断是否有_after_index方法
                        if($reflectionClass -> hasMethod(&#39;_after_index&#39;)){
                            $reflec_after_method = $reflectionClass -> getMethod(&#39;_after_index&#39;);
                            //判断是否是public
                            if($reflec_after_method -> isPublic()){
                                //执行_after_index方法
                                $reflec_after_method -> invoke($reflectionClass -> newInstance());

                            }else{
                                echo &#39;_after_index不是public修饰的&#39;;
                            }

                        }else{
                            echo &#39;没有_after_index方法&#39;;
                        }


                    }else{
                        echo &#39;_before_index修饰符不是public&#39;;
                    }

                }else{
                    echo &#39;没有_before_index方法&#39;;
                }


            }else{
                echo &#39;index方法不是public修饰&#39;;
            }


        }else{
            echo &#39;index方法不存在&#39;;
        }

    }else{
        echo &#39;类名不存在&#39;;
    }
    ......结果.......
    _before_index方法执行 
    data : 这是test的数据
    _after_index方法执行

在上面的代码中可以看到我们不停地在判断类中有没有某个方法,是不是public修饰,然后执行,我们可以利用封装的思想,把一些共性的特征抽取出来写成一个函数。从而对我们的代码进行优化。

优化的代码:

<?php

    class IndexAction{
        public function index(){
            echo &#39;index<br>&#39;;
        }

        public function _before_index(){
            echo &#39;_before_index方法执行 <br>&#39;;
        }

        public function test($data){
            echo &#39;data : &#39;  . $data . &#39;<br>&#39;;
        }

        public  function _after_index(){
            echo &#39;_after_index方法执行<br>&#39;;
        }
    }

    if(class_exists(&#39;IndexAction&#39;)){
        $reflectionClass = new ReflectionClass(&#39;IndexAction&#39;);
        //创建IndexAction对象。
        $indexAction = $reflectionClass -> newInstance();

        execute($reflectionClass,$indexAction,&#39;index&#39;);
        execute($reflectionClass,$indexAction,&#39;_after_index&#39;);
        execute($reflectionClass,$indexAction,&#39;test&#39;,&#39;test使用的数据&#39;);
        execute($reflectionClass,$indexAction,&#39;_after_index&#39;);
    }else{
        echo &#39;没有IndexAction方法&#39;;
    }

    //封装的函数
    /**
     * [execute description]对反射的封装。
     * @param  [type]  $reflect_obj [description]反射对象
     * @param  [type]  $worker      [description]类对象
     * @param  [type]  $name        [description]方法的名字
     * @param  [type]  $canshu      [description]方法的参数
     * @return boolean              [description]
     */
    function execute($reflect_obj,$indexAction,$name,$param = &#39;&#39;){
        if($reflect_obj-> hasMethod($name)){
            $method = $reflect_obj->getMethod($name);
        if($method->isPublic()){
            $method->invoke($indexAction,$param); 
        }else{
            echo $name . &#39;不是public&#39;;
        }
        }else{
            echo $name . &#39;方法不存在&#39;;
        }
    }
    ......结果.....
    index
    _after_index方法执行
    data : test使用的数据
    _after_index方法执行

可以看到进行功能的封装,可以简化我们的代码,同时代码看起来更加的清晰。

总结

PHP的面向对象的内容到这里算是讲完了,在开发中利用面向对象的思想进行开发是一定要掌握的技能。同时也要对面向对象进行深度的了解。

 以上就是PHP,反射、对象序列化的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn