0%

PHP8 常量:定义、使用与高级特性

PHP8 常量:定义、使用与高级特性

常量是在脚本执行过程中值不能改变的标识符,与变量相比,常量具有全局可见性(默认情况下)和不可修改的特性。PHP8 对常量的处理进行了增强,提供了更灵活的定义方式和更多功能。本文将详细介绍 PHP8 中常量的定义、类型、作用域及新特性。

常量的基本概念与定义方式

1. 常量的特点

  • 常量的值在定义后不能被修改或重新定义
  • 常量默认具有全局作用域,可在脚本任何地方访问
  • 常量名通常使用大写字母,多个单词用下划线分隔(如 MAX_SIZE
  • 常量可以是标量类型(整数、浮点数、字符串、布尔值)或数组,PHP7 后支持类常量为数组

2. 定义常量的方式

(1)define() 函数(传统方式)

define() 函数是定义常量的传统方式,适用于全局常量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// 定义标量常量
define('PI', 3.14159);
define('SITE_NAME', 'My Website');
define('ENABLED', true);

// 定义数组常量(PHP7+支持)
define('FRUITS', ['apple', 'banana', 'cherry']);

// 使用常量(无需$符号)
echo PI; // 输出:3.14159
echo SITE_NAME; // 输出:My Website
echo ENABLED ? '启用' : '禁用'; // 输出:启用
echo FRUITS[1]; // 输出:banana
?>

(2)const 关键字(推荐方式)

const 关键字在 PHP5.3+ 引入,是定义常量的语言结构,比 define() 更高效,推荐优先使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
// 定义标量常量
const VERSION = '1.0.0';
const MAX_USERS = 100;
const DEBUG_MODE = false;

// 定义数组常量
const CONFIG = [
'host' => 'localhost',
'port' => 8080
];

// 使用常量
echo VERSION; // 输出:1.0.0
echo MAX_USERS; // 输出:100
echo CONFIG['host']; // 输出:localhost
?>

(3)define()const 的区别
特性 define() 函数 const 关键字
定义位置 可在函数、条件语句中定义 只能在全局作用域或类内部定义
常量名 可动态生成(如变量作为名称) 必须是字面量,不能动态生成
数组支持 PHP7+ 支持 PHP7+ 支持
类常量 不支持 支持(类内部定义)
性能 稍低 更高(编译时解析)

类常量与接口常量

1. 类常量

在类内部使用 const 定义的常量,属于类的一部分,通过 类名::常量名 访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class MathUtils {
// 定义类常量
const PI = 3.1415926535;
const MAX_VALUE = 1000;

// 在类方法中使用常量
public function calculateCircleArea($radius) {
return self::PI * $radius * $radius;
}
}

// 访问类常量
echo MathUtils::PI; // 输出:3.1415926535

// 通过类实例访问(不推荐)
$math = new MathUtils();
echo $math::MAX_VALUE; // 输出:1000

// 调用使用了常量的方法
echo $math->calculateCircleArea(5); // 输出:78.5398163375
?>

2. 接口常量

接口中定义的常量,实现该接口的类都可以使用,且值不能被修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
interface Database {
const HOST = 'localhost';
const PORT = 3306;
}

class MySQL implements Database {
public function getConnectionInfo() {
return "Host: " . self::HOST . ", Port: " . self::PORT;
}
}

$db = new MySQL();
echo $db->getConnectionInfo(); // 输出:Host: localhost, Port: 3306
echo Database::HOST; // 直接访问接口常量:输出localhost
?>

3. PHP8 类常量可见性修饰符

PHP7.1+ 允许为类常量添加可见性修饰符(publicprivateprotected),控制常量的访问范围。

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
26
27
28
29
30
31
32
33
<?php
class User {
public const ROLE_GUEST = 'guest'; // 公开常量,任何地方可访问
protected const ROLE_USER = 'user'; // 受保护常量,类内部和子类可访问
private const ROLE_ADMIN = 'admin'; // 私有常量,仅类内部可访问

public function getRoles() {
// 类内部可访问所有常量
return [
self::ROLE_GUEST,
self::ROLE_USER,
self::ROLE_ADMIN
];
}
}

class AdminUser extends User {
public function getAdminRoles() {
return [
self::ROLE_GUEST, // 可访问公开常量
self::ROLE_USER // 可访问受保护常量
// self::ROLE_ADMIN // 错误:不能访问父类私有常量
];
}
}

$user = new User();
echo $user::ROLE_GUEST; // 正确:访问公开常量
// echo $user::ROLE_USER; // 错误:不能访问受保护常量

print_r($user->getRoles()); // 正确:类内部可访问所有常量
?>

魔术常量(Magic Constants)

PHP 提供了一组特殊的 “魔术常量”,它们的值会根据上下文自动变化,通常用于获取代码的元信息。

常用的魔术常量:

魔术常量 描述
__LINE__ 当前代码行号
__FILE__ 当前文件的完整路径和文件名
__DIR__ 当前文件所在目录
__FUNCTION__ 当前函数名
__CLASS__ 当前类名
__METHOD__ 当前类方法名
__NAMESPACE__ 当前命名空间名
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
<?php
echo "当前行号:" . __LINE__ . "<br>"; // 输出当前代码所在行号

echo "当前文件路径:" . __FILE__ . "<br>"; // 输出当前文件的完整路径

echo "当前目录:" . __DIR__ . "<br>"; // 输出当前文件所在目录

function testFunction() {
echo "当前函数名:" . __FUNCTION__; // 输出:testFunction
}
testFunction();

class TestClass {
public function testMethod() {
echo "<br>当前类名:" . __CLASS__; // 输出:TestClass
echo "<br>当前方法名:" . __METHOD__; // 输出:TestClass::testMethod
}
}
$obj = new TestClass();
$obj->testMethod();

namespace MyNamespace;
echo "<br>当前命名空间:" . __NAMESPACE__; // 输出:MyNamespace
?>

PHP8 常量新特性

1. 常量表达式增强

PHP8 允许在常量定义中使用更复杂的表达式,包括算术运算、字符串拼接等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// 算术运算表达式
const A = 10;
const B = 20;
const C = A + B; // 30
const D = (A * 2) / B; // 1

// 字符串拼接
const PREFIX = 'user_';
const USERNAME = PREFIX . 'john'; // 'user_john'

// 数组表达式
const NUMBERS = [1, 2, 3];
const MORE_NUMBERS = [...NUMBERS, 4, 5]; // [1, 2, 3, 4, 5]
?>

2. readonly 关键字与常量(PHP8.1+)

PHP8.1 引入的 readonly 关键字可用于类属性,使其初始化后不可修改,类似常量但作用于对象属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class Product {
public readonly string $name;
public readonly float $price;

public function __construct(string $name, float $price) {
$this->name = $name;
$this->price = $price;
}
}

$product = new Product("Laptop", 999.99);
echo $product->name; // 输出:Laptop

// $product->name = "Phone"; // 错误:Cannot modify readonly property
?>

常量的检测与命名空间

1. 检测常量是否存在

使用 defined() 函数检查常量是否已定义,避免使用未定义的常量导致错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if (defined('PI')) {
echo PI;
} else {
define('PI', 3.14);
echo "已定义PI:" . PI;
}

// 检查类常量
if (defined('MathUtils::PI')) {
echo MathUtils::PI;
}
?>

2. 命名空间中的常量

在命名空间中定义的常量,访问时需指定命名空间或使用 use 导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
namespace MyProject\Constants;

const MAX_WIDTH = 1024;
const MAX_HEIGHT = 768;

// 在同一命名空间中使用
echo MAX_WIDTH; // 输出:1024

// 在其他命名空间中访问
namespace OtherNamespace;

// 方法1:使用完整命名空间 如果使用完整的命名空间,需要以\开头,否则php会把它解析为OtherNamespace\MyProject\Constants\MAX_HEIGHT
echo \MyProject\Constants\MAX_HEIGHT; // 输出:768

// 方法2:使用use导入
use MyProject\Constants;
echo Constants\MAX_WIDTH; // 输出:1024

// 方法3:导入并起别名
use MyProject\Constants as C;
echo C\MAX_HEIGHT; // 输出:768
?>

常量使用最佳实践

  1. 优先使用 const 而非 define()const 是语言结构,解析更快,且支持类常量,代码更易读。
  2. 常量命名规范:使用全大写字母,多个单词用下划线分隔(如 ERROR_LEVEL),与变量名区分开。
  3. 合理使用常量可见性:类常量应根据需要添加 publicprotectedprivate 修饰符,限制访问范围,提高封装性。
  4. 避免滥用全局常量:过多的全局常量会污染全局命名空间,可考虑使用类常量或命名空间常量替代。
  5. 使用常量存储固定值:如配置参数、状态码、错误信息等不随程序运行变化的值,适合用常量存储,便于集中管理和修改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// 推荐:使用类常量存储相关的固定值
class HttpStatus {
const OK = 200;
const BAD_REQUEST = 400;
const NOT_FOUND = 404;
const INTERNAL_ERROR = 500;

// 状态码对应的消息
const MESSAGES = [
self::OK => 'Success',
self::BAD_REQUEST => 'Bad Request',
self::NOT_FOUND => 'Not Found',
self::INTERNAL_ERROR => 'Internal Server Error'
];
}

// 使用
http_response_code(HttpStatus::NOT_FOUND);
echo HttpStatus::MESSAGES[HttpStatus::NOT_FOUND]; // 输出:Not Found
?>

总结

PHP8 中的常量是存储固定值的重要机制,支持标量类型和数组,可在全局范围或类 / 接口中定义。const 关键字是推荐的定义方式,比 define() 函数更高效且功能更全面

欢迎关注我的其它发布渠道