我首选的检查常量是否设置的方法,如果未设置,则设置它(可用于在文件中设置默认值,用户已在另一个文件中设置了自己的值。)
<?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 次调用中 12ms 的开销不会让最终用户抓狂,但在与 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 - 拒绝目录列表。'));
?>
要检查特质中是否在使用特质的类中定义了常量,请在常量名称前加上 `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) ?>
如果 TEST 是用 define() 赋值的,那么你将收到它的值。如果不是,那么你将收到一个空字符串。
如果你能用更少的代码行来实现这个功能,或者做一些比切换错误处理程序更优化的操作,请告诉我。