ホームページ 类库下载 PHP类库 PHPの16のマジックメソッドを詳しく解説

PHPの16のマジックメソッドを詳しく解説

Oct 31, 2016 pm 01:40 PM
php

はじめに

PHP では、2 つのアンダースコア __ で始まるメソッドをマジック メソッドと呼びます。これらのメソッドは PHP において重要な役割を果たします。 マジックメソッドには、

__construct()、クラスコンストラクター

__destruct()、クラスデストラクター

__call()が含まれます。オブジェクト内でアクセスできないメソッドを呼び出す場合は、静的な方法で

__callStatic()を呼び出します。アクセスできないメソッドを呼び出す場合は、

__callStatic()を呼び出します。 、

__get() を呼び出し、クラスのメンバー変数を取得する場合は

__set() を呼び出し、クラスのメンバー変数を設定する場合は

__isset() を呼び出し、アクセスできないプロパティで isset() を呼び出します。または empty() は、アクセスできないプロパティに対して unset() が呼び出されたときに呼び出されます。

__sleep()、serialize()実行時、この関数が最初に呼び出されます

__wakeup()、unserialize()実行時、この関数が最初に呼び出されます

__toString()、クラスが次の場合の応答メソッド文字列として扱われる

__invoke()、関数

__set_state() を呼び出してオブジェクトを呼び出すときの応答メソッド、この静的メソッドは、クラスをエクスポートするために var_export() が呼び出されるときに呼び出されます。

__clone()、オブジェクトのコピーが完了したら

__autoload()を呼び出し、未定義クラスのロードを試みます

__debugInfo()、必要なデバッグ情報を出力します

フォームで説明しましょうこれらの魔法のメソッドの使用方法の例を以下に示します。

1. __construct()、クラスのコンストラクター関数

PHP のコンストラクター メソッドは、オブジェクトの作成後にオブジェクトによって自動的に呼び出される最初のメソッドです。すべてのクラスにコンストラクターがあり、明示的に宣言されていない場合、デフォルトでクラス内にパラメーターがなく空のコンテンツが存在します。

1. コンストラクター メソッドの役割

通常、コンストラクター メソッドは、オブジェクトの作成時にメンバーのプロパティに初期値を割り当てるなど、いくつかの便利な初期化タスクを実行するために使用されます。

2. クラス内でのコンストラクターメソッドの宣言形式

function __constrct([参数列表]){ 
 
  方法体 //通常用来对成员属性进行初始化赋值 
 
}
ログイン後にコピー

3. クラス内でコンストラクターメソッドを宣言する際の注意点

PHPはコンストラクターのオーバーロードをサポートしていないため、同じクラス内で宣言できるコンストラクターは1つだけです。

コンストラクター メソッドの名前は 2 つのアンダースコア __construct() で始まります

以下は例です:

<?php 
    class Person 
    {                                                                       
            public $name;         
            public $age;         
            public $sex;         
                                                                  
        /** 
         * 显示声明一个构造方法且带参数 
         */                                                                                        
        public function __construct($name="", $sex="男", $age=22) 
        {       
            $this->name = $name; 
            $this->sex = $sex; 
            $this->age = $age; 
        } 
         
        /** 
         * say 方法 
         */ 
        public function say() 
        {  
            echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age; 
        }    
                                                                                            
    }
ログイン後にコピー

パラメータなしでオブジェクト $person1 を作成します

$Person1 = new Person(); 
 
echo $Person1->say(); //输出:我叫:,性别:男,年龄:27
ログイン後にコピー

パラメータ "Xiao Ming" を使用してオブジェクト $person2 を作成します ”

$Person2 = new Person("小明"); 
 
echo $Person2->say(); //输出:我叫:张三,性别:男,年龄:27
ログイン後にコピー

3 つのパラメーターを使用してオブジェクト $person3 を作成します

$Person3 = new Person("李四","男",25); 
 
echo $Person3->say(); //输出:我叫:李四,性别:男,年龄:25
ログイン後にコピー

2. クラスのデストラクターである __destruct()

上記の説明を通じて、コンストラクター メソッドが何であるかはすでにわかりました。次に、構築メソッドに相当するのがデストラクター メソッドです。

デストラクター メソッドを使用すると、クラスを破棄する前に、ファイルを閉じる、結果セットを解放するなど、一部の操作を実行したり、一部の関数を完了したりできます。

デストラクターメソッドは、PHP5で導入された新しい内容です。

デストラクタメソッドの宣言形式は構築メソッド__construct()と同様で、2つのアンダースコアで始まるメソッド__destruct()でもあります。このデストラクタメソッドの名前も固定です。

1. デストラクターメソッドの宣言形式

function __destruct() 
 
{ 
 
  //方法体 
 
}
ログイン後にコピー

注: デストラクターにはパラメーターを含めることはできません。

2. デストラクター メソッドの役割

一般に、デストラクター メソッドは PHP ではあまり使用されず、クラスのオプションの部分であり、通常はオブジェクトが破棄される前にいくつかのクリーンアップ タスクを完了するために使用されます。

例は次のとおりです。

<?php 
class Person{      
                                                         
    public $name;          
    public $age;          
    public $sex;          
                                                                     
    public function __construct($name="", $sex="男", $age=22) 
    {    
        $this->name = $name; 
        $this->sex  = $sex; 
        $this->age  = $age; 
    } 
     
    /** 
     * say 说话方法 
     */ 
    public function say() 
    {   
        echo "我叫:".$this->name.",性别:".$this->sex.",年龄:".$this->age; 
    }     
     
    /** 
     * 声明一个析构方法 
     */ 
    public function __destruct() 
    { 
            echo "我觉得我还可以再抢救一下,我的名字叫".$this->name; 
    } 
} 
 
$Person = new Person("小明"); 
unset($Person); //销毁上面创建的对象$Person
ログイン後にコピー

実行時の上記のプログラム出力:

もう少し保存できると思います。私の名前は Xiao Ming

3 でアクセスできないメソッドを呼び出したときです。オブジェクトの転送。

このメソッドには 2 つのパラメーターがあります。最初のパラメーター $function_name は存在しないメソッド名を自動的に受け取り、2 番目の $arguments は存在しないメソッドの複数のパラメーターを配列の形式で受け取ります。

1. __call() メソッドの形式:

function __call(string $function_name, array $arguments) 
 
{ 
 
  // 方法体 
 
}
ログイン後にコピー

2. __call() メソッドの機能:

呼び出されたメソッドが存在せず、誤ってプログラムが終了してしまうことを避けるため、 __call() を使用してそれを回避できます。

このメソッドは、呼び出されたメソッドが存在しない場合に自動的に呼び出され、プログラムは引き続き実行されます。

次のコードを参照してください:

<?php 
class Person 
{                              
    function say() 
    {   
                               
           echo "Hello, world!<br>";  
    }       
         
    /** 
     * 声明此方法用来处理调用对象中不存在的方法 
     */ 
    function __call($funName, $arguments) 
    {  
          echo "你所调用的函数:" . $funName . "(参数:" ;  // 输出调用不存在的方法名 
          print_r($arguments); // 输出调用不存在的方法时的参数列表 
          echo ")不存在!<br>\n"; // 结束换行                       
    }                                           
} 
$Person = new Person();             
$Person->run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法 
$Person->eat("小明", "苹果");              
$Person->say();
ログイン後にコピー

実行結果:

你所调用的函数:run(参数:Array ( [0] => teacher ) )不存在! 
 
你所调用的函数:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在! 
 
Hello, world!
ログイン後にコピー

4. __callStatic()、静的モードでアクセスできないメソッドを呼び出すときに呼び出されます

このメソッドは、__callStatic を除き、上記の __call() 関数と同じです。 () が静的メソッドによって準備されていないことを除けば、その他はすべて同じです。

以下のコードを見てください:

<?php 
class Person 
{ 
    function say() 
    { 
 
        echo "Hello, world!<br>"; 
    } 
 
    /** 
     * 声明此方法用来处理调用对象中不存在的方法 
     */ 
    public static function __callStatic($funName, $arguments) 
    { 
        echo "你所调用的静态方法:" . $funName . "(参数:" ;  // 输出调用不存在的方法名 
        print_r($arguments); // 输出调用不存在的方法时的参数列表 
        echo ")不存在!<br>\n"; // 结束换行 
    } 
} 
$Person = new Person(); 
$Person::run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法 
$Person::eat("小明", "苹果"); 
$Person->say();
ログイン後にコピー

実行結果は次のとおりです:

你所调用的静态方法:run(参数:Array ( [0] => teacher ) )不存在! 
 
你所调用的静态方法:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在! 
 
Hello, world!
ログイン後にコピー

5. __get()、クラスのメンバー変数を取得するときに呼び出されます

PHP オブジェクト指向プログラミングでは、メンバー属性の後にクラスのプロパティが private に設定されている場合、外部から呼び出そうとすると、「プライベート プロパティにアクセスできません」というエラーが発生します。したがって、この問題を解決するには、魔法のメソッド __get() を使用できます。

マジックメソッド__get()の役割

プログラムの実行中に、オブジェクトの外部にあるプライベートメンバー属性の値を取得するために使用できます。

次の __get() インスタンスを通じてさらに接続してみましょう:

<?php 
class Person 
{ 
    private $name; 
    private $age; 
 
    function __construct($name="", $age=1) 
    { 
        $this->name = $name; 
        $this->age = $age; 
    } 
 
    /** 
     * 在类中添加__get()方法,在直接获取属性值时自动调用一次,以属性名作为参数传入并处理 
     * @param $propertyName 
     * 
     * @return int 
     */ 
    public function __get($propertyName) 
    {    
        if ($propertyName == "age") { 
            if ($this->age > 30) { 
                return $this->age - 10; 
            } else { 
                return $this->$propertyName; 
            } 
        } else { 
            return $this->$propertyName; 
        } 
    } 
} 
$Person = new Person("小明", 60);   // 通过Person类实例化的对象,并通过构造方法为属性赋初值 
echo "姓名:" . $Person->name . "<br>";   // 直接访问私有属性name,自动调用了__get()方法可以间接获取 
echo "年龄:" . $Person->age . "<br>";    // 自动调用了__get()方法,根据对象本身的情况会返回不同的值
ログイン後にコピー

実行結果:

姓名:小明 
 
年龄:50
ログイン後にコピー

6. __set()、クラスのメンバー変数を設定するときに

__set() を呼び出す関数:

__set ( $property, $value )` メソッドは、未定義のプロパティに値を割り当てるときに使用され、設定されるプロパティの名前と値がトリガーされます。

请看下面的演示代码:

<?php 
class Person 
{ 
    private $name; 
    private $age; 
 
    public function __construct($name="",  $age=25) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
    } 
 
    /** 
     * 声明魔术方法需要两个参数,真接为私有属性赋值时自动调用,并可以屏蔽一些非法赋值 
     * @param $property 
     * @param $value 
     */ 
    public function __set($property, $value) { 
        if ($property=="age") 
        { 
            if ($value > 150 || $value < 0) { 
                return; 
            } 
        } 
        $this->$property = $value; 
    } 
 
    /** 
     * 在类中声明说话的方法,将所有的私有属性说出 
     */ 
    public function say(){ 
        echo "我叫".$this->name.",今年".$this->age."岁了"; 
    } 
} 
 
$Person=new Person("小明", 25); //注意,初始值将被下面所改变 
//自动调用了__set()函数,将属性名name传给第一个参数,将属性值”李四”传给第二个参数 
$Person->name = "小红";     //赋值成功。如果没有__set(),则出错。 
//自动调用了__set()函数,将属性名age传给第一个参数,将属性值26传给第二个参数 
$Person->age = 16; //赋值成功 
$Person->age = 160; //160是一个非法值,赋值失效 
$Person->say();  //输出:我叫小红,今年16岁了
ログイン後にコピー

运行结果:

我叫小红,今年16岁了
ログイン後にコピー

七、 __isset(),当对不可访问属性调用isset()或empty()时调用

在看这个方法之前我们看一下isset()函数的应用,isset()是测定变量是否设定用的函数,传入一个变量作为参数,如果传入的变量存在则传回true,否则传回false。

那么如果在一个对象外面使用isset()这个函数去测定对象里面的成员是否被设定可不可以用它呢?

分两种情况,如果对象里面成员是公有的,我们就可以使用这个函数来测定成员属性,如果是私有的成员属性,这个函数就不起作用了,原因就是因为私有的被封装了,在外部不可见。那么我们就不可以在对象的外部使用isset()函数来测定私有成员属性是否被设定了呢?当然是可以的,但不是一成不变。你只要在类里面加上一个__isset()方法就可以了,当在类外部使用isset()函数来测定对象里面的私有成员是否被设定时,就会自动调用类里面的__isset()方法了帮我们完成这样的操作。

__isset()的作用:当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。

请看下面代码演示:

<?php 
class Person 
{ 
    public $sex; 
    private $name; 
    private $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    /** 
     * @param $content 
     * 
     * @return bool 
     */ 
    public function __isset($content) { 
        echo "当在类外部使用isset()函数测定私有成员{$content}时,自动调用<br>"; 
        echo  isset($this->$content); 
    } 
} 
 
$person = new Person("小明", 25); // 初始赋值 
echo isset($person->sex),"<br>"; 
echo isset($person->name),"<br>"; 
echo isset($person->age),"<br>";
ログイン後にコピー

运行结果如下:

1 // public 可以 isset() 
 
当在类外部使用isset()函数测定私有成员name时,自动调用 // __isset() 内 第一个echo 
 
1 // __isset() 内第二个echo 
 
当在类外部使用isset()函数测定私有成员age时,自动调用 // __isset() 内 第一个echo 
 
1 // __isset() 内第二个echo
ログイン後にコピー

八、 __unset(),当对不可访问属性调用unset()时被调用。

看这个方法之前呢,我们也先来看一下 unset() 函数,unset()这个函数的作用是删除指定的变量且传回true,参数为要删除的变量。

那么如果在一个对象外部去删除对象内部的成员属性用unset()函数可以吗?

这里自然也是分两种情况:

1、 如果一个对象里面的成员属性是公有的,就可以使用这个函数在对象外面删除对象的公有属性。

2、 如果对象的成员属性是私有的,我使用这个函数就没有权限去删除。

虽然有以上两种情况,但我想说的是同样如果你在一个对象里面加上__unset()这个方法,就可以在对象的外部去删除对象的私有成员属性了。在对象里面加上了__unset()这个方法之后,在对象外部使用“unset()”函数删除对象内部的私有成员属性时,对象会自动调用__unset()函数来帮我们删除对象内部的私有成员属性。

请看如下代码:

<?php 
class Person 
{ 
    public $sex; 
    private $name; 
    private $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    /** 
     * @param $content 
     * 
     * @return bool 
     */ 
    public function __unset($content) { 
        echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>"; 
        echo  isset($this->$content); 
    } 
} 
 
$person = new Person("小明", 25); // 初始赋值 
unset($person->sex); 
unset($person->name); 
unset($person->age);
ログイン後にコピー

运行结果:

当在类外部使用unset()函数来删除私有成员时自动调用的 
 
1当在类外部使用unset()函数来删除私有成员时自动调用的 
 
1
ログイン後にコピー

九、 __sleep(),执行serialize()时,先会调用这个函数

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,则该方法会优先被调用,然后才执行序列化操作。

此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。

如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

注意:

__sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。

作用:

__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

具体请参考如下代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    /** 
     * @return array 
     */ 
    public function __sleep() { 
        echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>"; 
        $this->name = base64_encode($this->name); 
        return array(&#39;name&#39;, &#39;age&#39;); // 这里必须返回一个数值,里边的元素表示返回的属性名称 
    } 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
echo serialize($person); 
echo &#39;<br/>&#39;;
ログイン後にコピー

代码运行结果:

当在类外部使用serialize()时会调用这里的__sleep()方法 
 
O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}
ログイン後にコピー

十、 __wakeup(),执行unserialize()时,先会调用这个函数

如果说 __sleep() 是白的,那么 __wakeup() 就是黑的了。

那么为什么呢?

因为:

与之相反,`unserialize()` 会检查是否存在一个 `__wakeup()` 方法。如果存在,则会先调用 `__wakeup` 方法,预先准备对象需要的资源。

作用:

__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

还是看代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    /** 
     * @return array 
     */ 
    public function __sleep() { 
        echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>"; 
        $this->name = base64_encode($this->name); 
        return array(&#39;name&#39;, &#39;age&#39;); // 这里必须返回一个数值,里边的元素表示返回的属性名称 
    } 
 
    /** 
     * __wakeup 
     */ 
    public function __wakeup() { 
        echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>"; 
        $this->name = 2; 
        $this->sex = &#39;男&#39;; 
        // 这里不需要返回数组 
    } 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
var_dump(serialize($person)); 
var_dump(unserialize(serialize($person)));
ログイン後にコピー

运行结果:

当在类外部使用serialize()时会调用这里的__sleep()方法 
 
string(58) "O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}" 当在类外部使用serialize()时会调用这里的__sleep()方法 
 
当在类外部使用unserialize()时会调用这里的__wakeup()方法 
 
object(Person)#2 (3) { ["sex"]=> string(3) "男" ["name"]=> int(2) ["age"]=> int(25) }
ログイン後にコピー

十一、 __toString(),类被当成字符串时的回应方法

作用:

__toString() 方法用于一个类被当成字符串时应怎样回应。例如 `echo $obj;` 应该显示些什么。

注意:

此方法必须返回一个字符串,否则将发出一条 `E_RECOVERABLE_ERROR` 级别的致命错误。

警告:

不能在 __toString() 方法中抛出异常。这么做会导致致命错误。

代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    public function __toString() 
    { 
        return  &#39;go go go&#39;; 
    } 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值
ログイン後にコピー

结果:

go go go
ログイン後にコピー

那么如果类中没有 __toString() 这个魔术方法运行会发生什么呢?让我们来测试下:

代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
     
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
echo $person;
ログイン後にコピー

结果:

Catchable fatal error: Object of class Person could not be converted to string in D:\phpStudy\WWW\test\index.phpon line 18
ログイン後にコピー

很明显,页面报了一个致命错误,这是语法所不允许的。

十二、 __invoke(),调用函数的方式调用一个对象时的回应方法

作用:

当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

注意:

本特性只在 PHP 5.3.0 及以上版本有效。

直接上代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    public function __invoke() { 
        echo &#39;这可是一个对象哦&#39;; 
    } 
 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
$person();
ログイン後にコピー

查看运行结果:

这可是一个对象哦
ログイン後にコピー

当然,如果你执意要将对象当函数方法使用,那么会得到下面结果:

Fatal error: Function name must be a string in D:\phpStudy\WWW\test\index.php on line 18
ログイン後にコピー

十三、 __set_state(),调用var_export()导出类时,此静态方法会被调用。

作用:

自 PHP 5.1.0 起,当调用 var_export() 导出类时,此静态方法会被自动调用。

参数:

本方法的唯一参数是一个数组,其中包含按 array('property' => value, ...) 格式排列的类属性。

下面我们先来看看在没有加 __set_state() 情况按下,代码及运行结果如何:

上代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
var_export($person);
ログイン後にコピー

看结果:

Person::__set_state(array( &#39;sex&#39; => &#39;男&#39;, &#39;name&#39; => &#39;小明&#39;, &#39;age&#39; => 25, ))
ログイン後にコピー

很明显,将对象中的属性都打印出来了

加了 __set_state() 之后:

继续上代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    public static function __set_state($an_array) 
    { 
        $a = new Person(); 
        $a->name = $an_array[&#39;name&#39;]; 
        return $a; 
    } 
 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
$person->name = &#39;小红&#39;; 
var_export($person);
ログイン後にコピー

继续看结果:

Person::__set_state(array( &#39;sex&#39; => &#39;男&#39;, &#39;name&#39; => &#39;小红&#39;, &#39;age&#39; => 25, ))
ログイン後にコピー

十四、 __clone(),当对象复制完成时调用

在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果你有一个 GTK 窗口对象,该对象持有窗口相关的资源。你可能会想复制一个新的窗口,保持所有属性与原来的窗口相同,但必须是一个新的对象(因为如果不是新的对象,那么一个窗口中的改变就会影响到另一个窗口)。还有一种情况:如果对象 A 中保存着对象 B 的引用,当你复制对象 A 时,你想其中使用的对象不再是对象 B 而是 B 的一个副本,那么你必须得到对象 A 的一个副本。

作用:

对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。

语法:

$copy_of_object = clone $object;

注意:

当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。

当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。

看代码:

<?php 
class Person 
{ 
    public $sex; 
    public $name; 
    public $age; 
 
    public function __construct($name="",  $age=25, $sex=&#39;男&#39;) 
    { 
        $this->name = $name; 
        $this->age  = $age; 
        $this->sex  = $sex; 
    } 
 
    public function __clone() 
    { 
        echo __METHOD__."你正在克隆对象<br>"; 
    } 
 
} 
 
$person = new Person(&#39;小明&#39;); // 初始赋值 
$person2 = clone $person; 
 
var_dump(&#39;persion1:&#39;); 
var_dump($person); 
echo &#39;<br>&#39;; 
var_dump(&#39;persion2:&#39;); 
var_dump($person2);
ログイン後にコピー

看结果:

Person::__clone你正在克隆对象 
 
string(9) "persion1:" object(Person)#1 (3) { ["sex"]=> string(3) "男" ["name"]=> string(6) "小明" ["age"]=> int(25) } 
 
string(9) "persion2:" object(Person)#2 (3) { ["sex"]=> string(3) "男" ["name"]=> string(6) "小明" ["age"]=> int(25) }
ログイン後にコピー

克隆成功。

十五、__autoload(),尝试加载未定义的类

作用:

你可以通过定义这个函数来启用类的自动加载。

在魔术函数 __autoload() 方法出现以前,如果你要在一个程序文件中实例化100个对象,那么你必须用include或者require包含进来100个类文件,或者你把这100个类定义在同一个类文件中 —— 相信这个文件一定会非常大,然后你就痛苦了。

但是有了 __autoload() 方法,以后就不必为此大伤脑筋了,这个类会在你实例化对象之前自动加载制定的文件。

还是通过例子来看看吧:

先看看以往的方式:

/**  
 * 文件non_autoload.php  
 */  
    
require_once(&#39;project/class/A.php&#39;);   
require_once(&#39;project/class/B.php&#39;);   
require_once(&#39;project/class/C.php&#39;);   
    
if (条件A) {   
    $a = new A();   
    $b = new B();   
    $c = new C();   
    // … 业务逻辑   
} else if (条件B) {   
    $a = newA();   
    $b = new B();   
    // … 业务逻辑   
}
ログイン後にコピー

看到了吗?不用100个,只是3个看起来就有点烦了。而且这样就会有一个问题:如果脚本执行“条件B”这个分支时,C.php这个文件其实没有必要包含。因为,任何一个被包含的文件,无论是否使用,均会被php引擎编译。如果不使用,却被编译,这样可以被视作一种资源浪费。更进一步,如果C.php包含了D.php,D.php包含了E.php。并且大部分情况都执行“条件B”分支,那么就会浪费一部分资源去编译C.php,D.php,E.php三个“无用”的文件。

那么如果使用 __autoload() 方式呢?

/**  
 * 文件autoload_demo.php  
 */  
function  __autoload($className) {   
    $filePath = “project/class/{$className}.php”;   
    if (is_readable($filePath)) {   
        require($filePath);   
    }   
}   
    
if (条件A) {   
    $a = new A();   
    $b = new B();   
    $c = new C();   
    // … 业务逻辑   
} else if (条件B) {   
    $a = newA();   
    $b = new B();   
    // … 业务逻辑   
}
ログイン後にコピー

ok,不论效率怎么用,最起码界面看起来舒服多了,没有太多冗余的代。

再来看看这里的效率如何,我们分析下:

当php引擎第一次使用类A,但是找不到时,会自动调用 __autoload 方法,并将类名“A”作为参数传入。所以,我们在 __autoload()中需要的做的就是根据类名,找到相应的文件,并包含进来,如果我们的方法也找不到,那么php引擎就会报错了。

注意:

这里可以只用require,因为一旦包含进来后,php引擎再遇到类A时,将不会调用__autoload,而是直接使用内存中的类A,不会导致多次包含。

扩展:

其实php发展到今天,已经有将 `spl_autoload_register` — 注册给定的函数作为 __autoload 的实现了,但是这个不在啊本文讲解之内,有兴趣可以自行看手册。

十六、__debugInfo(),打印所需调试信息

注意:

该方法在PHP 5.6.0及其以上版本才可以用,如果你发现使用无效或者报错,请查看啊你的版本。

看代码:

<?php 
class C { 
    private $prop; 
 
    public function __construct($val) { 
        $this->prop = $val; 
    } 
 
    /** 
     * @return array 
     */ 
    public function __debugInfo() { 
        return [ 
            &#39;propSquared&#39; => $this->prop ** 2, 
        ]; 
    } 
} 
 
var_dump(new C(42));
ログイン後にコピー

结果:

object(C)#1 (1) { ["propSquared"]=> int(1764) }
ログイン後にコピー

再次注意:

这里的 `**` 是乘方的意思,也是在PHP5.6.0及其以上才可以使用,详情请查看PHP手册

总结

以上就是PHP中我了解到的魔术方法了,常用的包括 __set() __get() __autoload() 等应该熟悉,其他的了解也没有关系,毕竟知识不怕多嘛。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Dec 24, 2024 pm 04:42 PM

PHP 8.4 では、いくつかの新機能、セキュリティの改善、パフォーマンスの改善が行われ、かなりの量の機能の非推奨と削除が行われています。 このガイドでは、Ubuntu、Debian、またはその派生版に PHP 8.4 をインストールする方法、または PHP 8.4 にアップグレードする方法について説明します。

今まで知らなかったことを後悔している 7 つの PHP 関数 今まで知らなかったことを後悔している 7 つの PHP 関数 Nov 13, 2024 am 09:42 AM

あなたが経験豊富な PHP 開発者であれば、すでにそこにいて、すでにそれを行っていると感じているかもしれません。あなたは、運用を達成するために、かなりの数のアプリケーションを開発し、数百万行のコードをデバッグし、大量のスクリプトを微調整してきました。

PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 Dec 20, 2024 am 11:31 AM

Visual Studio Code (VS Code とも呼ばれる) は、すべての主要なオペレーティング システムで利用できる無料のソース コード エディター (統合開発環境 (IDE)) です。 多くのプログラミング言語の拡張機能の大規模なコレクションを備えた VS Code は、

JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 Apr 05, 2025 am 12:04 AM

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

PHPでHTML/XMLを解析および処理するにはどうすればよいですか? PHPでHTML/XMLを解析および処理するにはどうすればよいですか? Feb 07, 2025 am 11:57 AM

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

母音を文字列にカウントするPHPプログラム 母音を文字列にカウントするPHPプログラム Feb 07, 2025 pm 12:12 PM

文字列は、文字、数字、シンボルを含む一連の文字です。このチュートリアルでは、さまざまな方法を使用してPHPの特定の文字列内の母音の数を計算する方法を学びます。英語の母音は、a、e、i、o、u、そしてそれらは大文字または小文字である可能性があります。 母音とは何ですか? 母音は、特定の発音を表すアルファベットのある文字です。大文字と小文字など、英語には5つの母音があります。 a、e、i、o、u 例1 入力:string = "tutorialspoint" 出力:6 説明する 文字列「TutorialSpoint」の母音は、u、o、i、a、o、iです。合計で6元があります

PHPでの後期静的結合を説明します(静的::)。 PHPでの後期静的結合を説明します(静的::)。 Apr 03, 2025 am 12:04 AM

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。

PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? Apr 03, 2025 am 12:03 AM

PHPの魔法の方法は何ですか? PHPの魔法の方法には次のものが含まれます。1。\ _ \ _コンストラクト、オブジェクトの初期化に使用されます。 2。\ _ \ _リソースのクリーンアップに使用される破壊。 3。\ _ \ _呼び出し、存在しないメソッド呼び出しを処理します。 4。\ _ \ _ get、dynamic属性アクセスを実装します。 5。\ _ \ _セット、動的属性設定を実装します。これらの方法は、特定の状況で自動的に呼び出され、コードの柔軟性と効率を向上させます。

See all articles