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 = 'THREE 的值是 '.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 則註記

tmp dot 4 dot longoria at gmail dot com
13 年前
可以在基底類別中宣告常數,並在子類別中覆寫它,並且可以使用 'get_called_class' 方法從靜態方法存取正確的常數值。
<?php
abstract class 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`"

?>
kuzawinski dot marcin at gmail dot com
10 年前
從 PHP 5.6 開始,您終於可以使用數學表達式定義常數,就像這樣:

<?php

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

?>

我真開心 :)
匿名
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()」這樣的寫法完全違背了常數的用途。常數就應該是常數值,在每次執行時都保持不變。它們不應該在每次腳本運行或類別被實例化時改變。

結論:不要試圖把常數當作變數來使用。如果常數不適用,就直接使用變數。這樣你就不需要重新發明方法來實現已經存在的功能。
delete dot this dot and dot dots dot gt at kani dot hu
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
?>
Xiong Chiamiov
10 年前
const 也可以直接在命名空間中使用,這項功能在文件中從未明確說明。

<?php
# foo.php
namespace Foo;

const
BAR = 1;
?>

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

var_dump(Foo\BAR); // => int(1)
?>
jimmmy dot chief at gmail dot com
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;
}
}
?>

以及繼承自 a 類別的 b 類別

<?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

?>
nepomuk at nepda dot de
8 年前
[編者註:從 PHP 5.6.0 版開始,這已經是可行的。]

請注意,從 PHP 7 開始,可以使用陣列定義類別常數。

<?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"
}
*/
?>
powtac at gmx dot de
1 年前
由於說明文件中沒有提到,以下類型可以被設定為類別常數:字串、陣列、整數、布林值,或許也包含浮點數。但不包含物件。

<?php

類別 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)
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] - 寬度已被限制為最大值
Dimension [width=14, height=0] - 高度已被限制為最小值
Dimension [width=240, height=80] - 寬度和高度未變
- - - - - - - -

在您的類別中設定上下限也有助於讓您的物件更有意義。例如,Dimension 的寬度或高度不可能是負數。您有責任防止虛假輸入損壞您的物件,並避免程式碼其他部分發生潛在的錯誤和例外。
Paul
9 年前
方括號或大括號語法通常可以用於存取字串中的單個位元組(字元)。例如:$mystring[5]。但是,請注意,(由於某種原因)字串類別常數不接受此語法(至少在 PHP 5.5.12 中不接受)。
例如,以下程式碼會產生「PHP 解析錯誤:語法錯誤,在第 6 行的 php shell 程式碼中出現意外的 '['」。
<?php
類別 SomeClass
{
const
SOME_STRING = '0123456790';
public static function
ATest()
{
return
self::SOME_STRING[0];
}
}
?>
看起來您必須改用變數/類別成員。
Nimja
7 年前
請注意,這個魔術常數並不會載入類別。事實上,它甚至可以作用於不存在的類別。

這表示它不會干擾自動載入。

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

將輸出

字串(7) "Foo\Bar"
布林(false)
David Spector
6 年前
可以使用常見的逗號分隔語法來宣告多個常數

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

這顯示了一組適用於有限狀態機迴圈的列舉字面值的宣告。使用 "STATE::INIT" 之類的語法來參考此類列舉。在這種情況下,它的實際類型將是整數。
To Top