PHP 零基础教程

PHP 常量 (Constants)

常量(Constants)是用于存储简单值的标识符。顾名思义,常量一旦被定义,在脚本的整个执行过程中就不能被改变取消定义。它们与变量的最大区别就在于其值是固定不变的。

PHP 提供了两种主要的方式来定义常量:define() 函数和 const 关键字。

1. 使用 define() 定义常量

define() 是一个全局函数,用于在运行时(runtime)定义常量。它可以在类的定义之外使用,非常适合用来定义在整个脚本中都可以访问的全局常量。

define() 的语法如下:

define(string $name, mixed $value, bool $case_insensitive = false): bool
  • $name:常量的名称。通常的约定是使用全大写字母和下划线来命名常量。
  • $value:常量的值。这可以是一个标量值(整数、浮点数、字符串、布尔值)、一个数组或一个资源。
  • $case_insensitive:一个可选的布尔值参数。如果设置为 true,则该常量将不区分大小写。默认值为 false,即常量是区分大小写的。在现代 PHP 开发中,强烈不建议使用 true,因为这很容易引起代码混乱。

使用 define() 定义的常量在全局作用域中都有效。

1.1 define() 基础示例

<?php
// 定义一个区分大小写的常量,用于存储应用名称
define('APP_NAME', '我的超级应用');

// 定义一个数据库主机常量
define('DB_HOST', 'localhost');

// 定义一个最大文件大小常量(以字节为单位)
define('MAX_FILE_SIZE', 1024 * 1024 * 5); // 5 MB

echo '应用名称: ' . APP_NAME . '<br>';
echo '数据库主机: ' . DB_HOST . '<br>';
echo '最大文件大小: ' . MAX_FILE_SIZE . ' 字节<br>';

// 尝试重新定义一个已存在的常量会导致致命错误 (Fatal error)
// define('APP_NAME', '另一个应用'); // 这行代码会报错

// 访问一个不存在的常量
// echo NON_EXISTENT_CONSTANT; // 这会抛出一个 Notice 警告,并且什么都不输出
?>

在这个例子中,APP_NAMEDB_HOSTMAX_FILE_SIZE 被定义为常量。一旦定义,它们的值就无法再被修改。

1.2 define() 与数组

从 PHP 7 开始,define() 也可以用来定义包含数组值的常量。

<?php
// 定义一个数组常量,存储允许的图片类型
define('ALLOWED_IMAGE_TYPES', ['image/jpeg', 'image/png', 'image/gif']);

// 访问数组常量中的特定元素
echo '第一个允许的图片类型: ' . ALLOWED_IMAGE_TYPES[0] . '<br>';

// 遍历数组常量
echo '所有允许的图片类型:<br>';
foreach (ALLOWED_IMAGE_TYPES as $type) {
    echo '- ' . $type . '<br>';
}
?>

这个例子展示了如何定义一个数组常量,并访问和遍历它的元素。这对于存储一组固定的列表值非常有用。

1.3 在条件语句中使用 define()

使用 define() 定义常量的一大优势是,它可以在条件语句块内部执行。这允许你根据特定条件(例如不同的环境设置)动态地定义常量。

<?php
$environment = 'development'; // 可能是 'production' (生产环境), 'staging' (测试环境) 等

if ($environment === 'development') {
    define('DEBUG_MODE', true);
    define('API_BASE_URL', 'http://dev.api.example.com');
} else {
    define('DEBUG_MODE', false);
    define('API_BASE_URL', 'https://api.example.com');
}

echo '调试模式: ' . (DEBUG_MODE ? '已开启' : '已关闭') . '<br>';
echo 'API 基础地址: ' . API_BASE_URL . '<br>';
?>

在这里,DEBUG_MODEAPI_BASE_URL 会根据 $environment 变量的值被赋予不同的内容。这是管理项目配置信息的一种常见模式。

2. 使用 const 关键字定义常量

const 关键字用于在编译时(compile time)定义常量。这意味着使用 const 定义的常量必须声明在脚本的顶层作用域,或者在类/接口的内部(作为类常量,我们将在后续章节详细讲解)。

不能在函数、循环、if 语句或 try...catch 块内部使用 const

const 的语法更加简洁:

const NAME = value;
  • NAME:常量的名称,通常也是全大写字母加下划线。
  • value:常量的值。可以是标量值、数组或资源。在较老的 PHP 版本(5.6 之前)中,const 的值不支持表达式(例如函数调用、数学运算)。但在现代 PHP(PHP 5.6+)中,const 允许使用标量表达式。对于数组,它的工作原理与 define() 类似。

使用 const 定义的常量始终是区分大小写的。

2.1 const 基础示例

<?php
// 定义一个网站域名的常量
const WEBSITE_DOMAIN = 'example.com';

// 定义一个默认主题的常量
const DEFAULT_THEME = 'dark';

// 定义一个数字常量
const PI = 3.14159;

echo '网站域名: ' . WEBSITE_DOMAIN . '<br>';
echo '默认主题: ' . DEFAULT_THEME . '<br>';
echo '圆周率 PI 的值: ' . PI . '<br>';

// 尝试在函数内部定义 const 会导致解析错误 (Parse error)
/*
function myFunction() {
    const MY_CONSTANT = 'value'; // 解析错误
}
*/
?>

在这个例子中,WEBSITE_DOMAINDEFAULT_THEMEPI 使用 const 定义,它们的值在代码编译时就已经确定。

2.2 const 配合表达式 (PHP 5.6+)

现代 PHP 版本(5.6 及更高)允许 const 使用标量表达式来定义值。

<?php
// 使用数学表达式定义常量
const TWO_PI = 2 * PI; // 注意:PI 必须提前定义,例如 const PI = 3.14159;
const MAX_DIMENSION = 1920 + 1080; // 简单的算术运算

echo '两倍的 PI: ' . TWO_PI . '<br>';
echo '最大尺寸总和: ' . MAX_DIMENSION . '<br>';

// 在表达式中使用其他已定义的常量
const APP_VERSION = '1.0';
const APP_FULL_VERSION = APP_VERSION . '.0-beta'; // 字符串拼接

echo '应用完整版本: ' . APP_FULL_VERSION . '<br>';
?>

这说明了 const 可以使用简单的表达式(包括其他已定义的常量)来计算其最终的值。

2.3 const 定义数组常量

define() 类似,const 也可以定义存储数组的常量。

<?php
// 定义一个存储应用设置的数组常量
const APP_SETTINGS = [
    'locale' => 'zh_CN',
    'timezone' => 'Asia/Shanghai',
    'items_per_page' => 20
];

echo '应用语言环境: ' . APP_SETTINGS['locale'] . '<br>';
echo '每页显示数量: ' . APP_SETTINGS['items_per_page'] . '<br>';

// 遍历数组常量
echo '应用设置列表:<br>';
foreach (APP_SETTINGS as $key => $value) {
    echo '- ' . $key . ': ' . $value . '<br>';
}
?>

3. define()const 的区别

虽然 define()const 都可以创建常量,但它们有几个关键的特性差异:

特性对比define() 函数const 关键字
定义时机运行时 (可以在函数、循环内执行)编译时 (必须在顶层作用域)
作用域始终是全局的全局,或者类级别 (后续讲解)
大小写敏感可以通过第三个参数设置为不敏感 (极不推荐)始终敏感
支持的值类型标量、数组、资源标量、数组、资源
表达式支持支持表达式、函数调用等结果作为值仅限简单的标量表达式 (PHP 5.6+)
使用上下文全局空间、函数内、if 条件语句内全局空间、类/接口内部

最佳实践: 在现代 PHP 开发中,通常首推使用 const 来定义常量。因为它是编译时的,具有微小的性能优势,并且能强制实行更严格的常量定义规范。只有当你必须在条件语句、函数内部定义常量,或者常量的值需要由运行时的函数调用来决定时,才使用 define()

4. 检查常量是否存在

你可以使用 defined() 函数来检查一个常量是否已经被定义。这在防止重复定义报错,或者在常量缺失时提供默认值时非常有用。

<?php
// 在使用或定义常量之前,先检查它是否存在
if (!defined('DB_PASS')) {
    define('DB_PASS', 'secure_password');
}

echo '数据库密码: ' . DB_PASS . '<br>';

// 检查 APP_NAME 常量
if (defined('APP_NAME')) {
    echo 'APP_NAME 已定义。<br>';
} else {
    echo 'APP_NAME 未定义。<br>';
}
?>