01 · THE IDEAREAD → TRY → LEARN
Why constants belong to a class
Suppose a shop gives free standard shipping at 5000 cents. If the number 5000 is scattered through your code, nobody knows what it means and changing it is risky. A class constant gives the value a name and a home. The value is fixed, it is stored once per class rather than once per object, and you read it without creating an instance.
Declaring and reading constants
You declare a constant with const inside a class body and read it with the scope resolution operator, ClassName::NAME. Inside the class you can use self::NAME. Constants are often used for a fixed vocabulary, such as statuses, and a constant may hold an array of other constants.
class Status
{
public const DRAFT = 'draft';
public const PUBLISHED = 'published';
public const ALL = [self::DRAFT, self::PUBLISHED];
}
echo Status::PUBLISHED, "\n";
echo json_encode(Status::ALL, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";published ["draft","published"]
Because ALL is built from the other constants, renaming a value later only requires one edit.
Visibility and types
Class constants are public by default. You can mark them private or protected to keep an internal rule hidden. Use public constants for values that callers legitimately need, such as a status name, and private ones for implementation details.
Since PHP 8.3 a constant can also declare a type such as int, string, bool, float or array. A typed constant documents intent and makes PHP reject a value of the wrong type.
class Discount
{
private const int MAX_PERCENT = 30;
public const string LABEL = 'discount';
public static function clamp(int $percent): int
{
return min(max($percent, 0), self::MAX_PERCENT);
}
}
echo Discount::LABEL, ':', Discount::clamp(45), "\n";
echo Discount::clamp(-5), "\n";discount:30 0
Code outside the class can read Discount::LABEL, but touching Discount::MAX_PERCENT would throw an Error. The public static method is the only door to the rule.
Other ways to fetch a constant
The special ::class constant gives the class name as a string. Since PHP 8.3 you can also fetch a constant whose name is stored in a variable with Class::{$name}. The constant() function accepts a string such as 'Plan::FREE'.
class Plan
{
public const FREE = 0;
public const PRO = 15;
}
$name = 'PRO';
echo Plan::{$name}, "\n";
echo constant(Plan::class . '::FREE'), "\n";
echo Plan::class, "\n";15 0 Plan
Dynamic lookup is handy for mapping input to a rule, but validate the name first, because an unknown constant throws an Error.
Inheritance and final
A child class may redefine a parent's constant. If the parent declares it final, which is possible since PHP 8.1, the child cannot. Mark a constant final when its value is a rule that subclasses must never change. Interfaces can also declare constants, and since PHP 8.3 an implementing class must not make an interface constant less visible.
Common mistakes
- Writing
$this->MAXor$MAXinstead ofself::MAX. Constants have no dollar sign and are not object properties. - Using
self::where a child should be able to override the value.self::always points at the class that wrote the code. - Putting changing data in a constant. A constant is a rule, not state.
- Leaving a number unnamed in a comparison. Name it, then compare against the name.
- Using a loose boundary such as
>when the rule says "at least". Test the exact boundary value.
Exercise contract
Write shippingCostCents(int $subtotalCents, string $method): ?int, using a ShippingRules class for its numbers.
- A negative subtotal returns
null. - Method
standardcosts 499, but is free (0) when the subtotal is at least 5000. - Method
expressalways costs 1299. - Any other method returns
null.
The starter already declares the constants. Your work is to use them in the function instead of repeating the numbers. Tests check the returned values, including the 4999 and 5000 boundary.
Recap
Class constants name fixed domain values, are shared by the whole class and are read with ::. Control access with visibility, protect rules with final, and describe values with types in PHP 8.3 and later. Reference them everywhere instead of repeating literals.
Functions · Arrays · Types
- Use visible constants to define stable domain rules
- Implement and test a deterministic PHP 8.4 function