PHPClass Constants

Class Constants

Some values genuinely never change once a class is written — a maximum discount percentage, a status code, a currency symbol. Storing these as regular properties invites accidental reassignment somewhere deep in the code; PHP's const keyword inside a class fixes the value permanently, at compile time, for every instance and even before any instance exists.

Declaring a class constant

Constants on the Product class

PHP
<?php
class Product {
    const MAX_DISCOUNT_PERCENT = 50;
    const CURRENCY = 'USD';

    public string $name;
    public float $price;

    public function __construct(string $name, float $price)
    {
        $this->name = $name;
        $this->price = $price;
    }
}

echo Product::MAX_DISCOUNT_PERCENT, "\n";
echo Product::CURRENCY, "\n";
50
USD

Notice there's no $ in front of a constant's name, unlike properties — MAX_DISCOUNT_PERCENT, not $MAX_DISCOUNT_PERCENT. And unlike a static property, a constant can never be reassigned after it's declared; PHP raises a fatal error at compile time if you try.

self:: from inside, ClassName:: from outside

Inside the class's own methods, refer to a constant with self::CONST_NAME. Outside the class, use the class name: ClassName::CONST_NAME.

Applying a discount, capped by the class constant

PHP
<?php
class Product {
    const MAX_DISCOUNT_PERCENT = 50;

    public function __construct(
        public string $name,
        public float $price,
    ) {
    }

    public function applyDiscount(float $percent): float
    {
        $percent = min($percent, self::MAX_DISCOUNT_PERCENT);
        return $this->price * (1 - $percent / 100);
    }
}

$keyboard = new Product('Keyboard', 100.0);

echo $keyboard->applyDiscount(20), "\n";
echo $keyboard->applyDiscount(90), "\n"; // capped at 50%
80
50

applyDiscount() uses self::MAX_DISCOUNT_PERCENT because it's reading the constant from inside Product itself. A caller outside the class, though, would write Product::MAX_DISCOUNT_PERCENTself only makes sense once you're already inside a class body.

Visibility on constants (PHP 7.1+)

As of PHP 7.1, class constants accept the same visibility modifiers as properties and methods: public (the default, visible everywhere), protected (visible in the class and its subclasses), and private (visible only inside the declaring class).

Restricting a constant to internal use

PHP
<?php
class Order {
    public const STATUS_PENDING = 'pending';
    public const STATUS_SHIPPED = 'shipped';

    // an internal implementation detail, not part of the public API
    private const INTERNAL_RETRY_LIMIT = 3;

    public function summarize(): string
    {
        return 'Retry limit: ' . self::INTERNAL_RETRY_LIMIT;
    }
}

$order = new Order();
echo $order->summarize(), "\n";
echo Order::STATUS_PENDING, "\n";
Retry limit: 3
pending
Attempting to reach a private constant from outside fails
`Order::INTERNAL_RETRY_LIMIT` from outside the class is a fatal error — "Cannot access private constant." Visibility on constants works exactly like visibility on properties: it's about *where the code lives*, not about which object is asking.
final constants (PHP 8.1+)

Ordinarily, a subclass is allowed to redeclare an inherited constant with a different value — the same way it can override a method. PHP 8.1 added the final modifier for constants specifically to close that door when you want a value to be truly fixed for the entire class hierarchy, not just the base class.

Locking a constant against overrides

PHP
<?php
class Product {
    final public const TAX_RATE = 0.08;
}

class DigitalProduct extends Product {
    // Fatal error: Cannot override final constant TAX_RATE
    // public const TAX_RATE = 0.0;
}
final applies per-constant, not to the whole class
You can mark individual constants `final` while leaving others in the same class free to be overridden by subclasses — it's a per-declaration modifier, just like visibility.
A teaser: enums as a more modern alternative

A common use of class constants is modeling a small, fixed set of related values — order statuses, payment types, shipping tiers. That pattern works, but it has a weakness: Order::STATUS_PENDING is just a string under the hood, so nothing stops a typo like 'pendng' from silently compiling and failing only at runtime. PHP 8.1 introduced enums as a purpose-built alternative for exactly this scenario, giving you real type-checked values instead of loose strings or integers. Enums are a big enough topic to deserve their own page — for now, just know that if you find yourself writing a cluster of related constants like the Order example above, an enum is worth considering.

  • const NAME = value; inside a class declares a value that can never be reassigned.

  • Use self::CONST_NAME inside the class, ClassName::CONST_NAME outside it.

  • Constants support public / protected / private visibility since PHP 7.1.

  • final on a constant (PHP 8.1+) stops subclasses from redeclaring it with a different value.

  • For a fixed set of related values, consider a PHP enum instead of a cluster of constants.

Tip
Reach for a class constant whenever a "magic value" — a percentage cap, a status string, a config key — appears in more than one place in a class. Naming it turns a silent typo risk into a single well-documented source of truth, and IDEs will autocomplete `ClassName::` for you.