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