php: about this、self、parent、get_class

根据官方文档,关于php里面的$thisselfparent的区别是这样的:

  • $this是一个伪变量,是指向当前对象实例的引用
  • self是指向当前类的引用
  • parent是指向父类的引用

看下面这个例子:

class Base {
     public function __construct() {
          echo 'Base construct' . PHP_EOL;
          var_dump(get_class());
          var_dump(get_class($this));
      }
  }
 
  class Imp extends Base {
 
      public function __construct() {
          parent::__construct();
          echo 'Imp construct' . PHP_EOL;
          var_dump(get_class());
          var_dump(get_class($this));
      }
  }
 
  $base = new Base();
  $imp = new Imp();

打印的结果是:

Base construct
string(4) "Base"
string(4) "Base"
Base construct
string(4) "Base"
string(3) "Imp"
Imp construct
string(3) "Imp"
string(3) "Imp"

可以看到,在子类Imp中,$this一直是代表Imp的实例;在父类Base中,如果是父类的实例调用到该方法则$this代表Base,如果是子类的实例调用到该方法则$this代表Imp

self可以访问本类中的静态属性和静态方法,使用self时可以不用实例化。self一般的用法是使用::来调用相关属性和方法。示例如下:

<?php 
class A {
    public static $id = 0;
    public static $name = 'nemo';
    
    
    public function __construct($valId=1, $valName='default') {
        self::$id = $valId;
        self::$name = $valName;
    }
    
    public function info() {
        return array(
            'id' => self::$id,
            'name' => self::$name,
            );
    }
}

echo A::$id;
echo "\n";
echo A::$name;
echo "\n";

$var = new A();
var_dump($var->info());
	

打印结果是:

0
nemo
array(2) {
  ["id"]=>
  int(1)
  ["name"]=>
  string(7) "default"
}

**注意:**静态属性和静态方法是属于类的。当在类的实例里面对静态属性进行变更之后,该类的其他实例也会受到影响

parent是指向父类的指针,使用parent时可以不用实例化。比如说上方的代码里面,在子类Imp的构造函数里面parent::__construct()调用了父类Base的构造函数。


关于is_a()方法,在PHP5.3的时候还闹过漏洞,具体是这样的:

照理说is_a()是用来判断一个变量是不是某个类的实例或者变量是不是某个类的子类的实例,但是在php5.3以及之前,如果判断结果是false的话,还会自动加载__autoload这个类。

用下面的代码来举例子

function __autoload($class) {
    echo "Would load: " . $class . PHP_EOL;
}
$var = "test";
var_dump(is_a($var, 'B'));
$obj = new Stdclass;
var_dump(is_a($obj, 'C'));

在php5.3的时候,这个代码执行的会加载BC类。但是在php5.4上就不会自动加载了。

据说php官方在当时还坚持认为这不是一个漏洞,后来是否是因为影响太大而修复了这个bug就不得而知了。

在代码里面尽量不要用is_a,而改用instanceof来判断某个变量是否是类或者父类的子类的实例。

 class Base {
     public function __construct() {
          echo 'Base construct' . PHP_EOL;
          var_dump(get_class());
          var_dump(get_class($this));
      }
  }
 
  class Imp extends Base {
 
      public function __construct() {
          parent::__construct();
          echo 'Imp construct' . PHP_EOL;
          var_dump(get_class());
          var_dump(get_class($this));
      }
  }
 
  $base = new Base();
  $imp = new Imp();
  
  $ret = $base instanceof Base;
  var_dump($ret);
  $ret = $imp instanceof Base;
  var_dump($ret);

以上代码,instanceof的结果都是true。


用来判断变量所属的类还有上面提到的get_class()方法,它返回的是一个字符串。不过使用的时候要注意namespace

比如说下面这个例子,在namespace Test里面声明了一个class A,在namespace T2里面也声明了一个class A。在不同的地方使用get_class返回的结果是不一样的,这与namespace有关。

 <?php
 
  namespace Test;
  class A {
  }
 
  $var = new A();
  var_dump(get_class($var));
 
  namespace T2;
  class B {
  }
 
  $v2 = new B();
  var_dump(get_class($v2));
 
  class A {
  }
  $v3 = new A();
  var_dump(get_class($v3));
  ?>

打印结果就是:

string(6) "Test\A"
string(4) "T2\B"
string(4) "T2\A"

如果再用instanceof来判断的话,那么

 <?php
 
  namespace Test;
  class A {
  }
 
  $var = new A();
  var_dump(get_class($var));
  var_dump($var instanceof A);
  var_dump($var instanceof Test\A);

  namespace T2;
  class B {
  }
 
  $v2 = new B();
  var_dump(get_class($v2));
 
  class A {
  }
  $v3 = new A();
  var_dump(get_class($v3));
  var_dump($v3 instanceof A);
  var_dump($v3 instanceof Test\A);
  var_dump($v3 instanceof T2\A);

  ?>

打印结果是:

string(6) "Test\A"
bool(true)
bool(false)
string(4) "T2\B"
string(4) "T2\A"
bool(true)
bool(false)
bool(false)

我会在下面一片笔记里面讲到namespace使用时候的注意点。

Show Comments