PHP Conference Japan 2024

类常量

可以在每个类基础上定义常量,保持其相同且不可更改。类常量的默认可见性为public

注意:

子类可以重新定义类常量。从 PHP 8.1.0 开始,如果类常量被定义为final,则子类不能重新定义它。

接口也可以拥有常量。查看接口文档以获取示例。

可以使用变量来引用类。变量的值不能是关键字(例如 selfparentstatic)。

请注意,类常量每个类只分配一次,而不是每个类实例分配一次。

示例 #1 定义和使用常量

<?php
class MyClass
{
const
CONSTANT = 'constant value';

function
showConstant() {
echo
self::CONSTANT . "\n";
}
}

echo
MyClass::CONSTANT . "\n";

$classname = "MyClass";
echo
$classname::CONSTANT . "\n";

$class = new MyClass();
$class->showConstant();

echo
$class::CONSTANT."\n";
?>

特殊的::class常量允许在编译时进行完全限定类名解析,这对于命名空间类很有用。

示例 #2 命名空间 ::class 示例

<?php
namespace foo {
class
bar {
}

echo
bar::class; // foo\bar
}
?>

示例 #3 类常量表达式示例

<?php
const ONE = 1;
class
foo {
const
TWO = ONE * 2;
const
THREE = ONE + self::TWO;
const
SENTENCE = 'The value of THREE is '.self::THREE;
}
?>

示例 #4 类常量可见性修饰符,从 PHP 7.1.0 开始

<?php
class Foo {
public const
BAR = 'bar';
private const
BAZ = 'baz';
}
echo
Foo::BAR, PHP_EOL;
echo
Foo::BAZ, PHP_EOL;
?>

以上示例在 PHP 7.1 中的输出

bar

Fatal error: Uncaught Error: Cannot access private const Foo::BAZ in …

注意:

从 PHP 7.1.0 开始,允许为类常量使用可见性修饰符。

示例 #5 类常量可见性差异检查,从 PHP 8.3.0 开始

<?php

interface MyInterface
{
public const
VALUE = 42;
}

class
MyClass implements MyInterface
{
protected const
VALUE = 42;
}
?>

以上示例在 PHP 8.3 中的输出

Fatal error: Access level to MyClass::VALUE must be public (as in interface MyInterface) …

注意从 PHP 8.3.0 开始,对可见性差异的检查更加严格。在此版本之前,类常量的可见性可以与实现接口中常量的可见性不同。

示例 #6 获取类常量语法,从 PHP 8.3.0 开始

<?php
class Foo {
public const
BAR = 'bar';
private const
BAZ = 'baz';
}

$name = 'BAR';
echo
Foo::{$name}, PHP_EOL; // bar
?>

注意:

从 PHP 8.3.0 开始,可以使用变量动态获取类常量。

添加注释

用户贡献的注释 12 条注释

206
tmp dot 4 dot longoria at gmail dot com
13 年前
可以在基类中声明常量,并在子类中重写它,并且可以通过 'get_called_class' 方法从静态方法访问常量的正确值。


<?php
抽象类 dbObject
{
const
TABLE_NAME='undefined';

public static function
GetAll()
{
$c = get_called_class();
return
"SELECT * FROM `".$c::TABLE_NAME."`";
}
}

class
dbPerson extends dbObject
{
const
TABLE_NAME='persons';
}

class
dbAdmin extends dbPerson
{
const
TABLE_NAME='admins';
}

echo
dbPerson::GetAll()."<br>";//输出: "SELECT * FROM `persons`"
echo dbAdmin::GetAll()."<br>";//输出: "SELECT * FROM `admins`"

?>
144
[email protected]
10年前
从PHP 5.6开始,你终于可以使用数学表达式来定义常量,例如:

<?php

class MyTimer {
const
SEC_PER_DAY = 60 * 60 * 24;
}

?>

我开心:)
151
匿名用户
14年前
大多数人错过了声明常量的要点,并且通过尝试将函数或数组声明为常量来混淆事物。接下来会发生的事情是尝试比必要更复杂的事情,有时会导致不良的编码习惯。让我解释一下...

常量是值的名称(但它不是变量),它通常会在代码编译时被替换,而不是在运行时。

因此,无法使用函数的返回值,因为它们只会在运行时返回值。

无法使用数组,因为它们是在运行时存在的的数据结构。

声明常量的一个主要目的是通常在代码中使用一个值,你可以轻松地在一个地方替换它,而无需查找所有出现的位置。另一个是避免错误。

考虑一些之前其他人编写的示例

1. const MY_ARR = "return array(\"A\", \"B\", \"C\", \"D\");";
有人说,这将声明一个可以使用 eval 的数组。错误!这只是一个作为常量的字符串,而不是数组。如果可以将数组声明为常量,它是否有意义?可能不会。相反,将数组的值声明为常量并创建一个数组变量。

2. const magic_quotes = (bool)get_magic_quotes_gpc();
这当然不起作用。它也没有意义。该函数已经返回值,为同一件事声明一个常量没有意义。

3. 有人谈到了对常量的“动态”赋值。什么?对常量没有动态赋值,运行时赋值_仅_适用于变量。让我们来看一下建议的示例

<?php
/**
* 仅处理数据库的常量
*/
class DbConstant extends aClassConstant {
protected
$host = 'localhost';
protected
$user = 'user';
protected
$password = 'pass';
protected
$database = 'db';
protected
$time;
function
__construct() {
$this->time = time() + 1; // 动态赋值
}
}
?>

这些不是常量,而是类的属性。“this->time = time()”之类的东西甚至会完全违背常量的目的。常量应该只是常量值,在每次执行时都是如此。它们不应该在每次脚本运行或实例化类时都发生变化。

结论:不要试图将常量重新发明成变量。如果常量不起作用,只需使用变量即可。然后,你无需重新发明方法来实现已经存在的功能。
116
[email protected]
10年前
我认为如果我们在这里引起一些对延迟静态绑定的关注,那将很有用
<?php
class A {
const
MY_CONST = false;
public function
my_const_self() {
return
self::MY_CONST;
}
public function
my_const_static() {
return static::
MY_CONST;
}
}

class
B extends A {
const
MY_CONST = true;
}

$b = new B();
echo
$b->my_const_self ? 'yes' : 'no'; // 输出: no
echo $b->my_const_static ? 'yes' : 'no'; // 输出: yes
?>
93
Xiong Chiamiov
10年前
const 也可以直接在命名空间中使用,这是文档中从未明确说明的功能。

<?php
# foo.php
namespace Foo;

const
BAR = 1;
?>

<?php
# bar.php
require 'foo.php';

var_dump(Foo\BAR); // => int(1)
?>
48
[email protected]
8年前
嗨,我想指出 self::CONST 和 $this::CONST 在扩展类中的区别。
让我们有一个类 a

<?php
class a {
const
CONST_INT = 10;

public function
getSelf(){
return
self::CONST_INT;
}

public function
getThis(){
return
$this::CONST_INT;
}
}
?>

以及类 b(它扩展了 a)

<?php
class b extends a {
const
CONST_INT = 20;

public function
getSelf(){
return
parent::getSelf();
}

public function
getThis(){
return
parent::getThis();
}
}
?>

这两个类都具有相同名称的常量 CONST_INT。
当子类调用父类中的方法时,self 和 $this 的使用之间会有不同的输出。

<?php
$b
= new b();

print_r($b->getSelf()); //10
print_r($b->getThis()); //20

?>
28
[email protected]
8年前
[编辑注:从PHP 5.6.0开始,这已经是可能的。]

请注意,从PHP7开始,可以使用数组定义类常量。



<?php
MyClass
{
const
ABC = array('A', 'B', 'C');
const
A = '1';
const
B = '2';
const
C = '3';
const
NUMBERS = array(
self::A,
self::B,
self::C,
);
}
var_dump(MyClass::ABC);
var_dump(MyClass::NUMBERS);

// 结果:
/*
array(3) {
[0]=>
string(1) "A"
[1]=>
string(1) "B"
[2]=>
string(1) "C"
}
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
*/
?>
2
powtac at gmx dot de
1 年前
由于描述中未提及,以下类型可以设置为类常量:字符串、数组、整数、布尔值,可能还有浮点数。但不能是对象。

<?php

class Test {
const
arr = array();
const
string = 'string';
const
int = 99;
const
bool = true;
}

var_dump(new Test())::arr,
(new
Test())::string,
(new
Test())::int,
(new
Test())::bool
);

/* PHP 7.0.0+ 的输出:

array(0) {
}
string(6) "string"
int(99)
bool(true)
8
wbcarts at juno dot com
16 年前
使用 CONST 设置上限和下限

如果您的代码接受用户输入,或者您只需要确保输入的可接受性,则可以使用常量来设置上限和下限。注意:强烈建议使用一个强制执行限制的静态函数……查看下面的 clamp() 函数以了解其用法。

<?php

class Dimension
{
const
MIN = 0, MAX = 800;

public
$width, $height;

public function
__construct($w = 0, $h = 0){
$this->width = self::clamp($w);
$this->height = self::clamp($h);
}

public function
__toString(){
return
"Dimension [width=$this->width, height=$this->height]";
}

protected static function
clamp($value){
if(
$value < self::MIN) $value = self::MIN;
if(
$value > self::MAX) $value = self::MAX;
return
$value;
}
}

echo (new
Dimension()) . '<br>';
echo (new
Dimension(1500, 97)) . '<br>';
echo (new
Dimension(14, -20)) . '<br>';
echo (new
Dimension(240, 80)) . '<br>';

?>

- - - - - - - -
Dimension [width=0, height=0] - 默认大小
Dimension [width=800, height=97] - 宽度已被限制为 MAX
Dimension [width=14, height=0] - 高度已被限制为 MIN
Dimension [width=240, height=80] - 宽度和高度不变
- - - - - - - -

在您的类上设置上限和下限也有助于您的对象更有意义。例如,Dimension 的宽度或高度不可能为负数。您有责任防止虚假输入破坏您的对象,并避免代码其他部分出现潜在的错误和异常。
3
Paul
9 年前
通常可以使用方括号或花括号语法访问字符串中的单个字节(字符)。例如:$mystring[5]。但是,请注意(由于某种原因),此语法不被字符串类常量接受(至少在 PHP 5.5.12 中是这样)。
例如,以下代码在 php shell 代码的第 6 行给出“PHP 解析错误:语法错误,意外的 '['”。
<?php
class SomeClass
{
const
SOME_STRING = '0123456790';
public static function
ATest()
{
return
self::SOME_STRING[0];
}
}
?>
看起来您必须使用变量/类成员来代替。
2
Nimja
7 年前
请注意,此魔术常量不会加载类。实际上,它可以在不存在的类上工作。

这意味着它不会干扰自动加载。

<?php
$className
= \Foo\Bar::class;
var_dump($className);
var_dump(class_exists($className, false));
?>

将输出

string(7) "Foo\Bar"
bool(false)
0
David Spector
6 年前
可以使用常用的逗号分隔语法声明多个常量

class STATE
{
const INIT=0, NAME_SEEN=1, ADDR_SEEN=2;
}

这展示了声明一组枚举文字,适合在有限状态机循环中使用。使用诸如“STATE::INIT”之类的语法引用此类枚举。在这种情况下,它的实际类型将是整数。
To Top