PHP - 魔术方法

PHP - 魔术方法

本文引用http://www.jb51.net/article/96167.htm

1. __construct() 构造函数

类在实例化时自动调用的方法, 用于类的初始化, 在初始化的时候对该类的成员进行赋值

2. __destruct() 析构函数

在销毁一个类之前执行的一些操作和功能, 比如说关闭文件,释放结果集等.
注: 析构函数不能带任何参数

3. __call() 在对象中调用一个不可访问方法时调用

该方法有两个参数,第一个参数 $function_name 会自动接收不存在的方法名,第二个 $arguments 则以**索引**数组的方式接收不存在方法的多个参数
为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免.
该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。
<?php
class Person
{
  /**
   * 声明此方法用来处理调用对象中不存在的方法
   */
  function __call($funName, $arguments)
  { 
     echo "你所调用的函数:" . $funName . "(参数:" ; // 输出调用不存在的方法名
     print_r($arguments); // 输出调用不存在的方法时的参数列表
     echo ")不存在!<br>\n"; // 结束换行           
  }                     
}
$Person = new Person();      
$Person->run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person->eat("小明", "苹果");
// 输出结果
    // 你所调用的函数:run(参数:Array ( [0] => teacher ) )不存在!
    // 你所调用的函数:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!
    // Hello, world!

4. __callStatic() 在对象中调用一个不可访问方法时调用

此方法跟__call()基本一致, 区别在于__callStatic()方法是在类静态调用不存在的方法是自动调用的

5. __clone() 当对象复制完成时调用

作用:
对象复制可以通过 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='男')
  {
    $this->name = $name;
    $this->age = $age;
    $this->sex = $sex;
  }

  public function __clone()
  {
    echo __METHOD__."你正在克隆对象<br>";
  }

}

$person = new Person('小明'); // 初始赋值
$person2 = clone $person;

var_dump('persion1:');
var_dump($person);
echo '<br>';
var_dump('persion2:');
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) }
克隆成功。

6. __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(); 
  // … 业务逻辑 
}
当php引擎第一次使用类A,但是找不到时,会自动调用 __autoload 方法,并将类名“A”作为参数传入。所以,我们在 __autoload() 中需要的做的就是根据类名,找到相应的文件,并包含进来,如果我们的方法也找不到,那么php引擎就会报错了。
**注意**:
这里可以只用require,因为一旦包含进来后,php引擎再遇到类A时,将不会调用__autoload,而是直接使用内存中的类A,不会导致多次包含。
**扩展**:
其实php发展到今天,已经有将 `spl_autoload_register` — 注册给定的函数作为 __autoload 的实现了,但是这个不在啊本文讲解之内,有兴趣可以自行看手册

7. __get() 获得一个类的成员变量时调用

魔术方法__get()的作用
在程序运行过程中,通过它可以在对象的外部获取私有成员属性的值。
如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法
<?php
class Person
{
  private $name = '周更生';
  private $age = '32';

  function __construct($name="", $age=1)
  {
    $this->name = $name;
    $this->age = $age;
  }

  /**
   * 在类中添加__get()方法,在直接获取属性值时自动调用一次,以属性名作为参数传入并处理
   * @param $propertyName
   */
  public function __get($propertyName)
  {  
    return $this->$propertyName;
  }
}
$Person = new Person("小明", 60);  // 通过Person类实例化的对象,并通过构造方法为属性赋初值
echo "姓名:" . $Person->name . "<br>";  // 直接访问私有属性name,自动调用了__get()方法可以间接获取
echo "年龄:" . $Person->age . "<br>";  // 自动调用了__get()方法,根据对象本身的情况会返回不同的值
// 运行结果:
// 姓名:周更生
// 年龄:32

8. __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岁了

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

<?php
class Person
{
  public $sex;
  private $name;
  private $age;

  public function __construct($name="", $age=25, $sex='男')
  {
    $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
// 1
// 1

10. __unset(),当对不可访问属性调用unset()时被调用

<?php
class Person
{
  public $sex;
  private $name;
  private $age;

  /**
   * @param $content
   */
  public function __unset($content) {
    echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
    echo unset($this->$content);
  }
}

$person = new Person();
unset($person->sex);
unset($person->name);
unset($person->age);

11. __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='男')
  {
    $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('name', 'age'); // 这里必须返回一个数值,里边的元素表示返回的属性名称
  }
}

$person = new Person('小明'); // 初始赋值
echo serialize($person);
echo '<br/>';
// 代码运行结果:
// 当在类外部使用serialize()时会调用这里的__sleep()方法
// O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}

11. __debugInfo(),打印所需调试信息数

**注意**:
该方法在PHP 5.6.0及其以上版本才可以用,如果你发现使用无效或者报错,请查看你的版本
<?php
class C {
  private $prop;

  public function __construct($val) {
    $this->prop = $val;
  }

  /**
   * @return array
   */
  public function __debugInfo() {
    return [
      'propSquared' => $this->prop ** 2,
    ];
  }
}

var_dump(new C(42));
结果:
object(C)#1 (1) { ["propSquared"]=> int(1764) }
再次注意:
这里的 `**` 是乘方的意思,也是在PHP5.6.0及其以上才可以使用,详情请查看PHP手册
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值