PHP后期静态绑定实例、类常量、类静态属性区别笔记

最近在项目中看到一个”后期静态绑定”的用法,之前没有了解过,顺便测试了类常量和静态属性,补补课,特意记录下实例。

根据PHP手册”后期静态绑定“的介绍,一句话总结:在继承范围内,使用预留的关键字static表示程序运行时最初调用的类C,通过static::来访问类C中的常量、静态属性、静态方法(php version >= 5.3)。

不使用后期静态绑定

在演示实例前,我们先看一个不用”后期静态绑定”的例子(本例原型来自PHP手册用户笔记):

<?php
abstract class Abstarct_User {
    const TABLE_NAME = '';

    public static function getAll() {
        $called_class = get_called_class();
        return 'SELECT * FROM `' . $called_class::TABLE_NAME . '`';
    }
}

class Fan extends Abstarct_User {
    const TABLE_NAME = 'user';
}

class Star extends Abstarct_User {
    const TABLE_NAME = 'star';
}

var_dump(Fan::getAll(), Star::getAll());

运行结果:

php class_static.php
string(20) "SELECT * FROM `user`"
string(20) "SELECT * FROM `star`"

这个比较好理解,通过get_called_class()获取最初调用的类,然后访问类的常量(原型作者说这是常量的重载,实际测试发现抽象基类Abstarct_User中不定义TABLE_NAME也是可以的)

Tip: 代码第7行返回的SQL语句,TABLE_NAME加了反引号,可以区分MYSQL保留字,一般我们尽量不去用保留字,万一用了加上反引号也是可以的,是一种安全的措施。另外,单引号中可以使用反引号。
eg:

SELECT `select` FROM `order`;

使用后期静态绑定

下面演示用”后期静态绑定”代替get_called_class()的例子:

<?php
abstract class Abstarct_User {
    const TABLE_NAME = '';

    public static function getAll() {
        return 'SELECT * FROM `' . static::TABLE_NAME . '`';
    }
}

class Fan extends Abstarct_User {
    const TABLE_NAME = 'user';
}

class Star extends Abstarct_User {
    const TABLE_NAME = 'star';
}

var_dump(Fan::getAll(), Star::getAll());

可以看到只是在程序第6行做了调整,运行结果跟上面是完全一样的:

php class_static.php
string(20) "SELECT * FROM `user`"
string(20) "SELECT * FROM `star`"

类常量与类静态属性区别

不只是类常量,类静态属性运行结果也跟上面完全一致(把const TABLE_NAME 换成了static $table_name)

<?php
abstract class Abstarct_User {
    public static $table_name = '';

    public static function getAll() {
        $called_class = get_called_class();
        return 'SELECT * FROM `' . $called_class::$table_name . '`';
        // return 'SELECT * FROM `' . static::$table_name . '`';
    }
}

class Fan extends Abstarct_User {
    public static $table_name = 'user';
}

class Star extends Abstarct_User {
    public static $table_name = 'star';
}

var_dump(Fan::getAll(), Star::getAll());

既然类常量和类静态属性都可以,那么我们在实际生产中如何选择? 核心问题还是两则有什么本质区别,以下做了部分测试:

一、类常量和静态属性都支持重载,也都支持类和对象两种访问方式(对于类常量重载原来还怀疑PHP手册上用户的说法,看来实践才能明白)
0、类常量演示:

<?php
abstract class Abstarct_User {
    const TABLE_NAME = 'base';

    public static function getAll() {
        return 'SELECT * FROM `' . static::TABLE_NAME . '`';
    }
}

class Fan extends Abstarct_User {
}

class Star extends Abstarct_User {
    const TABLE_NAME = 'star';
}

$fan = new Fan();

var_dump(Fan::getAll(), Star::getAll(), $fan::TABLE_NAME, Fan::TABLE_NAME);

// result
// string(20) "SELECT * FROM `base`"
// string(20) "SELECT * FROM `star`"
// string(4) "base"
// string(4) "base"

1、类静态属性演示:

<?php
abstract class Abstarct_User {
    public static $table_name = 'base';

    public static function getAll() {
        return 'SELECT * FROM `' . static::$table_name . '`';
    }
}

class Fan extends Abstarct_User {
}

class Star extends Abstarct_User {
    public static $table_name = 'star';
}

$fan = new Fan();

var_dump(Fan::getAll(), Star::getAll(), $fan::$table_name, Fan::$table_name);

// result
// string(20) "SELECT * FROM `base`"
// string(20) "SELECT * FROM `star`"
// string(4) "base"
// string(4) "base"

二、类常量不能以$开头,类静态属性需要以$开头【php 手册上没有明确说明】

<?php
class Fan extends Abstarct_User {
    const $TABLE_NAME = 'user';
}
// Parse error: parse error, expecting `"identifier (T_STRING)"

class Star extends Abstarct_User {
    public static table_name = 'star';
}

// Parse error: parse error, expecting `"variable (T_VARIABLE)"

var_dump(Fan::$TABLE_NAME, Star::table_name);

三、类常量不能加访问权限控制符,只能是public; 类静态属性可以加

注:以上测试基于php 5.6.30

类常量和类静态属性区别:
0、类常量和静态属性都支持重载,也都支持类和对象两种访问访问。
1、类常量不能以$开头,类静态属性需要以$开头。
2、类常量不能加访问权限控制符,只能是public; 类静态属性可以加。
3、类常量大小写都可以,原则上一般大写,const关键字大小写都可以,一般小写。
4、类静态属性public static的顺序可以颠倒,一般是public static。
5、类常量和类静态属性都支持在类成员方法中通过self::来访问。

(全文完)

参考:
http://cn2.php.net/manual/zh/language.oop5.constants.php
http://cn2.php.net/manual/zh/language.oop5.late-static-bindings.php
http://wxb.github.io/2017/03/17/关于PHP静态和后期静态绑定.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注