self与$this区别
在类中 self关键字指向的是当前类,可以使用self访问类中静态变量1
2
3
4
5
6
7class StaticExample
{
static public $num = 0;
static punlic function hello(){
self::$num++;
}
}
而 $this 指向的是当前对象。注意,不能在静态方法中使用伪变量$this
PHP延迟静态绑定
在PHP中,函数一旦定义好了,那么类中的静态方法和属性就被绑定到函数了。
所谓延迟静态绑定,个人理解就是在程序运行时,根据实际情况调用静态方法和属性,
比如:B类继承A类,子类B 重写了A类中的 静态方法或者属性,那么延迟绑定就相当于子类覆盖了父类中的方法或者属性,
从而实现了动态调用子类的目的,这和c++中的多态比较类似1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class A{
static $name = "Tom";
public function printName(){
echo static::$name."\n";
// self::fun();
static::fun(); // 注意此处 *
}
static function fun(){
echo "A Class\n";
}
}
class B extends A{
static $name = "Jon";
static function fun(){
echo "B Class\n";
}
}
$obj = new B();
$obj->printName();
如果printName中的是 self::fun(),则结果如下1
2Tom
A Class
而如果使用的是static::fun(),则延迟静态绑定,结果如下1
2Join
B Class
final类和方法
final类和方法不能被改变,即final类不能有子类,以及final方法不能被覆写。1
2
3
4final class Checkout{
}
class IllegalCheckout extends Checkout{
}
这样会产生错误,final类不能被继承。1
2
3
4
5
6
7
8class Checkout{
final public function totalize(){
}
}
class IllegalCheckout extends Checkout{
public function totalize(){
}
}
这样也是错误的,totalize是final方法,不能重写。
拦截器(魔术方法)
“拦截器”可以“拦截”发送到未定义的方法和属性的消息。
常用拦截器方法:1
2
3
4
5__get($property) 访问未定义的属性时候,调用该方法
__set($property, $value) 给未定义属性设置值的时候,调用该方法
__isset($property) 对未定义属性调用isset()时,调用该方法
__unset($property) 对未定义属性调用unset()时,调用该方法
__call($property, $args_array) 调用未定义方法时,执行该方法
1、 get()和set()用于处理类中未声明的属性。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Person
{
public function __get($property)
{
$method = "get{$property}"; // 构建带有“get”的方法名
if (method_exists($this, $method)) { // 方法是否存在
return $this->$method();
}
}
public function getName()
{
return 'Bob';
}
public function getAge()
{
return 22;
}
}
$p = new Person();
echo $p->name;
上述代码会输出 Bob ,因为 name属性没有定义,就会方位get方法,而我们实现了通过在属性名前面加个“get”的方法,
如果方法存在就执行并返回。
2、isset()方法,会在用户在一个没有定义的属性上调用。如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Person
{
// ...
/*
* 当用户在没有定义的属性上调用isset方法时,会调用__isset.
*/
public function __isset($property)
{
$method = "get{$property}";
return method_exists($this, $method);
}
}
$p = new Person();
if (isset($p->name)) {
echo $p->name;
}
当用户想先检查name属性是否存在时,使用了isset方法,由于name属性不存在,则调用了我们
扩展的isset方法,用于片判断getName是否存在。
3、 set()方法当给没有定义的属性赋值时被调用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class Person
{
// ...
private $_name;
private $_age;
public function __set($property, $value)
{
$method = "set{$property}";
if (method_exists($this, $method)) {
return $this->$method($value);
}
}
public function setName($name)
{
$this->_name = $name;
if (!is_null($name)) {
$this->_name = strtoupper($this->_name); // 转化为大写
}
}
}
$p = new Person();
$p->name = 'wang';
name属性没有被定义,所以赋值时,会调用__set方法,然后调用setName方法。
4、当要调用的方法不存在时,会调用__call()方法,接收两个参数,参数1是方法的名称,参数2是所有参数的数组形式1
2
3
4
5
6
7
8
9
10
11class Person
{
public function __call($name, $arguments)
{
echo $name;
var_dump($arguments);
}
}
$p = new Person();
$p->getHobby('hello', 'world');
会输出1
2
3
4getHobby
array (size=2)
0 => string 'hello' (length=5)
1 => string 'world' (length=5)