图源:
语法
php常量的基本用途与其它语言类似,即在编译期而非运行期提供一种确定的、不会改变的值:
const PROGRAM_VERSION = '1.0.0';
const DB_VERSION = '1.0.0';
const AUTHOR = 'icexmoon';
这些常量通常用于定义软件版本号、作者信息等。
按习惯,常量名通常以全大写字母结合_
定义。
在Go语言是个例外,其变量和常量命名都不推荐使用
_
,所以常量命名只能是大小写字母的驼峰样式。
常量与超全局变量类似,一经定义,可以在任何地方使用:
function use_const(){
echo "the program version is :".PROGRAM_VERSION.PHP_EOL;
echo "the author is :".AUTHOR.PHP_EOL;
}
use_const();
// the program version is :1.0.0
// the author is :icexmoon
一般来说,常量必须被定义为基础类型的数值,或者在编译期可以评估结果的表达式(比如简单的数学运算):
const COUNT = 1 + 2 + 3;
const ARR = array(1, 2, 3);
const MSG = implode(',', array(1, 2, 3));
// Fatal error: Constant expression contains invalid operations in ...
但php提供一种特别的方式,可以“在运行时定义常量”:
define('MSG', implode(',', array(1, 2, 3)));
echo MSG.PHP_EOL;
// 1,2,3
使用一个没有定义的常量将产生错误:
<?php
echo MY_CONST.PHP_EOL;
// Fatal error: Uncaught Error: Undefined constant "MY_CONST" in ...
在php8.0以前,使用一个未定义的常量,可能会被解析为常量名称组成的字符串,并产生一个
E_NOTICE
级别的错误,在php8.0之后,会产生E_ERROR
。
可以使用defined
检查常量是否被定义:
if (defined('MSG')){
echo "MSG is defined".PHP_EOL;
// MSG is defined
}
可以通过constant()
函数传入包含常量名称的字符串来获取常量值:
<?php
$constName = 'MSG';
const MSG = 'hello';
echo constant($constName).PHP_EOL;
// hello
这在不知道常量名称,只有包含常量名称的变量时很有用。
使用get_defined_constants
可以获取当前已定义的所有常量:
<?php
$consts = get_defined_constants();
foreach ($consts as $constName => $constValue){
if (strpos($constName, 'E_')===0){
echo "name:{$constName} value:{$constValue}".PHP_EOL;
}
}
// name:E_ERROR value:1
// name:E_RECOVERABLE_ERROR value:4096
// name:E_WARNING value:2
// name:E_PARSE value:4
// name:E_NOTICE value:8
// name:E_STRICT value:2048
// ...
常量也可以定义在类中,这里以一个自定义异常类作为说明:
<?php
class UserException extends Exception
{
const ERROR_DB = 0;
const ERROR_OTHER = 1;
const ERROR_WEB = 2;
const ERROR_INPUT = 3;
private $errFlag;
private $msg;
private $exp;
public function __construct(?Exception $exp, string $msg, int $errFlag)
{
$this->errFlag = $errFlag;
$this->msg = $msg;
$this->exp = $exp;
}
public function getErrFlag(): int
{
return $this->errFlag;
}
public function getMsg(): string
{
return $this->msg;
}
}
try {
throw new UserException(null, "测试代码", UserException::ERROR_OTHER);
} catch (UserException $e) {
if ($e->getErrFlag() == UserException::ERROR_OTHER) {
echo "other error, reason is " . $e->getMsg() . PHP_EOL;
// other error, reason is 测试代码
}
}
这使用类常量来定义自定义异常类的错误类别,这在以前是一种相当常见的方式,当然从php8.1开始,可以使用枚举来取代。
此外,从php7.1.0开始,类常量可以使用访问修饰符了:
class UserException extends Exception
{
public const ERROR_DB = 0;
public const ERROR_OTHER = 1;
private const ERROR_WEB = 2;
protected const ERROR_INPUT = 3;
...
不过在我看来似乎作用不大,一般来说类常量是无需进行封装和保护的。
还需要注意的是,const
只能在最外部的作用域或类定义中使用:
<?php
function define_const(){
const MSG = "hello";
// Parse error: syntax error, unexpected token "const" ...
}
当然,define()
并没有这种限制:
function define_const(){
define("MSG","hello");
}
if (defined("MSG")){
echo MSG.PHP_EOL;
}
define_const();
if (defined("MSG")){
echo MSG.PHP_EOL;
// hello
}
预定义常量
php的预定义常量的来源很多,包括php内核、扩展等等,可能因为加载的模块不同而不同,这里展示一些常见的预定义常量:
<?php
function print_var($var)
{
echo $var . PHP_EOL;
}
print_var(PHP_VERSION); //PHP版本
// 8.1.0
print_var(PHP_OS); //当前操作系统
// WINNT
print_var(PHP_OS_FAMILY); //操作系统家族
// Windows
print_var(PHP_INT_MAX); //当前硬件平台支持的最大整形
// 9223372036854775807
print_var(PHP_BINARY); //php的二进制执行文件路径
// D:\software\Coding\php-8.1.0-nts-Win32-vs16-x64\php.exe
更多的预定义常量可以查看官方手册。
魔术常量
“魔术常量”其实并不是真正的常量,它们会随着执行代码的不同而不同,通常会保存当前代码的运行相关的环境信息,合理地使用魔术常量可以避免代码中出现不必要的“硬编码”:
include "d:/workspace/http/php-notes/ch5/const.php";
echo PROGRAM_VERSION.PHP_EOL;
echo AUTHOR.PHP_EOL;
// 1.0.0
// icexmoon
上面的代码有很明显的硬编码,这会使得当前应用的部署路径限定死了,只要部署的路径不对,代码就无法运行,甚至根本无法在Linux主机上部署代码,因为Linux压根不会有d:/...
这样的目录。
更合理的方式是使用魔术变量:
include __DIR__."/const.php";
当然这只是用于演示魔术变量的用途,实际上可以使用更灵活的写法:
include "./const.php";
对于一个完善的Web应用,往往会采用在配置文件中定义APP_ROOT
常量,其余地方都会使用include APP_ROOT.'/XXX.php'
魔术常量都以前后双下划线的方式命名,类似于__XXX__
。常用的魔术变量有:
-
__DIR__
,表示当前代码所在的目录路径。 -
__FILE__
,表示当前代码文件的路径。
完整的魔术常量列表见官方手册。
以上就是常量的相关内容,虽然这部分有点少,但我依然决定尽量以PHP手册的章节来组织笔记结构。
谢谢阅读。
文章评论