我首选的检查常量是否已设置的方法,如果未设置则设置它(可用于在文件中设置默认值,用户已在另一个文件中设置了自己的值)。
<?php
defined('CONSTANT') or define('CONSTANT', 'SomeDefaultValue');
?>
Dan。
(PHP 4、PHP 5、PHP 7、PHP 8)
defined — 检查是否存在具有给定名称的常量
检查是否定义了具有给定 constant_name
的常量。
注意:
如果要查看变量是否存在,请使用 isset(),因为 defined() 仅适用于 常量。如果要查看函数是否存在,请使用 function_exists()。
constant_name
常量名称。
示例 #1 检查常量
<?php
/* 注意引号的使用,这一点很重要。此示例检查
* 字符串'TEST'是否为名为TEST的常量的名称 */
if (defined('TEST')) {
echo TEST;
}
interface bar {
const test = 'foobar!';
}
class foo {
const test = 'foobar!';
}
var_dump(defined('bar::test')); // bool(true)
var_dump(defined('foo::test')); // bool(true)
?>
示例 #2 检查枚举成员(从 PHP 8.1.0 开始)
<?php
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
var_dump(defined('Suit::Hearts')); // bool(true)
?>
我首选的检查常量是否已设置的方法,如果未设置则设置它(可用于在文件中设置默认值,用户已在另一个文件中设置了自己的值)。
<?php
defined('CONSTANT') or define('CONSTANT', 'SomeDefaultValue');
?>
Dan。
// 检查类常量是否存在,如果类由变量引用。
class Class_A
{
const CONST_A = 'value A';
}
// 当类名已知时。
if ( defined( 'Class_A::CONST_A' ) )
echo 'Class_A::CONST_A defined';
// 使用类名变量。注意双引号。
$class_name = Class_A::class;
if ( defined( "$class_name::CONST_A" ) )
echo '$class_name::CONST_A defined';
// 使用实例化对象作为变量类。
$object_A = new $class_name();
if ( defined( get_class($object_A).'::CONST_A' ) )
echo '$object_A::CONST_A defined';
在使用 defined() 之前,请查看以下基准测试
true 0.65ms
$true 0.69ms (1)
$config['true'] 0.87ms
TRUE_CONST 1.28ms (2)
true 0.65ms
defined('TRUE_CONST') 2.06ms (3)
defined('UNDEF_CONST') 12.34ms (4)
isset($config['def_key']) 0.91ms (5)
isset($config['undef_key']) 0.79ms
isset($empty_hash[$good_key]) 0.78ms
isset($small_hash[$good_key]) 0.86ms
isset($big_hash[$good_key]) 0.89ms
isset($small_hash[$bad_key]) 0.78ms
isset($big_hash[$bad_key]) 0.80ms
PHP 版本 5.2.6,Apache 2.0,Windows XP
每个语句执行了 1000 次,虽然 1000 次调用中的 12 毫秒开销不会让最终用户抓狂,但在与 if(true) 进行比较时,它确实产生了一些有趣的结果
1) if($true) 几乎相同
2) if(TRUE_CONST) 几乎慢了两倍 - 我猜替换不是在编译时完成的(我必须仔细检查一下!)
3) 如果常量存在,则 defined() 慢 3 倍
4) 如果常量不存在,则 defined() 慢 19 倍!
5) isset() 非常高效,无论你向它抛出什么(对于任何实现数组驱动事件系统的人来说都是好消息 - 我!)
可能需要避免 if(defined('DEBUG'))...
您也可以在 defined 中使用静态后期命令“static::”。此示例按预期输出 -“int (2)”
<?php
abstract class class1
{
public function getConst()
{
return defined('static::SOME_CONST') ? static::SOME_CONST : false;
}
}
final class class2 extends class1
{
const SOME_CONST = 2;
}
$class2 = new class2;
var_dump($class2->getConst());
?>
不要忘记将常量的名称放在单引号中。你不会得到错误或警告。
<?php
define("AMOUNT_OF_APPLES", 12);
if(defined(AMOUNT_OF_APPLES)){
//这里不会输出任何内容
echo AMOUNT_OF_APPLES;
}
?>
所以改成这样
<?php
define("AMOUNT_OF_APPLES", 12);
if(defined("AMOUNT_OF_APPLES")){
//这里就可以输出了
echo AMOUNT_OF_APPLES;
}
//输出: 12
?>
我花了半天时间才发现这个问题...
我发现PHP没有枚举函数,所以我创建了自己的函数。这不是必须的,但有时会很有用。
<?php
function enum()
{
$args = func_get_args();
foreach($args as $key=>$arg)
{
if(defined($arg))
{
die('已定义常量 ' . $arg.' 重复定义');
}
define($arg, $key);
}
}
enum('ONE','TWO','THREE');
echo ONE, ' ', TWO, ' ', THREE;
?>
此函数以及constant()函数对命名空间敏感。如果将它们想象成始终在“根命名空间”下运行,可能会有所帮助。
<?php
namespace FOO\BAR
{
const WMP="wmp";
function test()
{
if(defined("WMP")) echo "直接: ".constant("WMP"); //不起作用;
elseif(defined("FOO\\BAR\\WMP")) echo "命名空间: ".constant("FOO\\BAR\\WMP"); //起作用
echo WMP; //起作用
}
}
namespace
{
\FOO\BAR\test();
}
在PHP5中,您实际上可以使用defined()来查看是否已定义对象常量,如下所示
<?php
class Generic
{
const WhatAmI = 'Generic';
}
if (defined('Generic::WhatAmI'))
{
echo Generic::WhatAmI;
}
?>
认为这可能值得注意。
-Nick
我发现了一些东西:如果引用丢失,defined()可能会变成false。
<?php
session_start(); // 创建 $_SESSION
define('SESSION_BACKUP', $_SESSION);
if (defined('SESSION_BACKUP')) echo 'A';
session_unset(); // 销毁 $_SESSION
if (defined('SESSION_BACKUP')) echo 'B';
?>
你会看到“A”,但看不到“B”。
如果常量的名称以反斜杠(\)开头,则无法使用defined()函数检测其是否存在,也无法使用constant()函数获取其值。
您可以使用get_defined_constants()函数检查其是否存在并获取其值,或者在常量名称前添加两个反斜杠(\\)。
<?php
define('\DOMAIN', 'wuxiancheng.cn');
$isDefined = defined('\DOMAIN'); // false
$domain = constant('\DOMAIN'); // NULL,在Php 8+中,您将收到一个致命错误。
var_dump($isDefined, $domain);
?>
<?php
define('\DOMAIN', 'wuxiancheng.cn');
$constants = get_defined_constants();
$isDefined = isSet($constants['\DOMAIN']);
$domain = $isDefined ? $constants['\DOMAIN'] : NULL;
var_dump($isDefined, $domain);
?>
<?php
define('\DOMAIN', 'wuxiancheng.cn');
$isDefined = defined('\\\DOMAIN');
$domain = constant('\\\DOMAIN');
var_dump($isDefined, $domain);
?>
在使用布尔类型的定义并假设通过defined()检查特定值时要小心,例如
<?php
define('DEBUG', false);
if(defined('DEBUG')){
echo '并非真正的调试模式';
}
?>
您还需要检查常量,如下所示
<?php
define('DEBUG', true);
if(defined('DEBUG') && DEBUG){
echo '确实是调试模式';
}
?>
defined()的作用仅仅是验证常量是否存在,而不是其值。
如果您希望保护文件免受直接访问,我通常使用以下方法
index.php
<?php
// 主要的代码在这里
define('START',microtime());
include "x.php";
?>
x.php
<?php
defined('START')||(header("HTTP/1.1 403 Forbidden")&die('403.14 - 拒绝目录列表。'));
?>
要在一个Trait中检查是否在使用该Trait的类中定义了常量,请在常量名称前加上`self::class`
<?php
trait MyTrait {
public function checkConstant() {
assert(defined(self::class . "::MY_CONSTANT"));
print self::MY_CONSTANT;
}
}
class MyClass {
use MyTrait;
protected const MY_CONSTANT = 'my value';
}
$class = new MyClass();
$class->checkConstant();
?>
您可能会发现,如果您使用<?= ?>来转储您的常量,并且它们未定义,则根据您的错误报告级别,您可能不会显示错误,而是仅显示常量的名称。例如
<?= TEST ?>
...可能会显示TEST而不是您预期的空字符串。解决方法是使用这样的函数
<?php
function C(&$constant) {
$nPrev1 = error_reporting(E_ALL);
$sPrev2 = ini_set('display_errors', '0');
$sTest = defined($constant) ? '已定义' : '未定义';
$oTest = (object) error_get_last();
error_reporting($nPrev1);
ini_set('display_errors', $sPrev2);
if ($oTest->message) {
return '';
} else {
return $constant;
}
}
?>
因此,现在您可以执行以下操作
<?= C(TEST) ?>
如果使用 define() 为 TEST 赋值,则您将收到该值。否则,您将收到一个空字符串。
如果您能用更少的代码行来实现此功能,或者能找到比切换错误处理程序更优化的方案,请发布。