Himanshu SharmaSoftware engineer
Let’s talk

PHP · Lesson 47 of 54

Static members and class constants

Use class constants, static properties and static methods in PHP, call them with ::, understand self and static, and write named constructors.

11 minObject-oriented PHPUpdated 22 October 2026

Awaiting technical review. This lesson is readable but not yet listed in search engines.

By the end of this lessonUse class constants, static methods and named constructors, and know when static is a poor choice.

Members of the class itself

Everything so far has belonged to objects: each product has its own name and price. Some things belong to the class as a whole: a tax rate that is the same for every product, a counter of how many orders were created, a function that builds a product from a database row. PHP marks these with const and static, and you reach them with the double colon :: (called the scope resolution operator) instead of ->.

Class constants

A class constant is a fixed value that belongs to a class. Inside the class, refer to it as self::NAME; outside, as ClassName::NAME:

php
<?php
class Product
{
    public const GST_RATE = 0.18;
    public const FREE_SHIPPING_FROM = 500;

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

    public function priceWithTax(): float
    {
        return round($this->price * (1 + self::GST_RATE), 2);
    }
}

$mug = new Product('Ceramic Mug Set', 18.75);
echo $mug->priceWithTax() . "\n";
echo "GST is " . Product::GST_RATE * 100 . "%\n";
echo "Free shipping from " . Product::FREE_SHIPPING_FROM . "\n";
result
22.13
GST is 18%
Free shipping from 500

Grouping constants in the class they belong to is tidier than global constants and makes their meaning clear. Constants can be public, protected or private, and since PHP 8.1 they can be final. For a fixed list of options such as statuses, an enum is usually better still.

Static methods

A static method is called on the class, without creating an object. Because there is no object, it cannot use $this. Static methods suit pure helpers that need no object state:

php
<?php
class Format
{
    public static function rupees(float $amount): string
    {
        return '₹' . number_format($amount, 2);
    }

    public static function percent(float $fraction): string
    {
        return round($fraction * 100, 1) . '%';
    }
}

echo Format::rupees(1499) . "\n";
echo Format::percent(0.1834) . "\n";
result
₹1,499.00
18.3%

Plain namespaced functions can do the same job; static helper classes are common in PHP mainly because classes are autoloaded and functions are not.

Named constructors

The most useful kind of static method creates objects. A class can only have one __construct(), but it can have several clearly named static factory methods, each turning a different kind of input into a valid object:

php
<?php
final class Money
{
    private function __construct(public readonly int $paise) {}

    public static function fromPaise(int $paise): self
    {
        return new self($paise);
    }

    public static function fromRupees(float $rupees): self
    {
        return new self((int) round($rupees * 100));
    }

    public static function zero(): self
    {
        return new self(0);
    }

    public function format(): string
    {
        return '₹' . number_format($this->paise / 100, 2);
    }
}

echo Money::fromRupees(89.5)->format() . "\n";
echo Money::fromPaise(1875)->format() . "\n";
echo Money::zero()->format() . "\n";
result
₹89.50
₹18.75
₹0.00

The constructor is private, so the only way to make a Money is through the named methods, which say exactly what the number means. fromRupees(89.5) cannot be confused with fromPaise(8950). You will see this pattern everywhere: DateTimeImmutable::createFromFormat(), Laravel's Carbon::parse(), and many more.

Static properties

A static property holds one value shared by the whole class, across every object:

php
<?php
class Order
{
    private static int $nextNumber = 1001;
    public readonly int $number;

    public function __construct()
    {
        $this->number = self::$nextNumber++;
    }
}

$a = new Order();
$b = new Order();
$c = new Order();
echo "$a->number $b->number $c->number\n";
result
1001 1002 1003

Note the $ in self::$nextNumber: static properties keep it, constants do not.

Be careful with static properties. A static property that anything can change is a global variable in disguise, with the same problems described in Variable scope, global and static: hidden dependencies and code that is hard to test. And remember that PHP starts fresh on every web request, so the counter above restarts at 1001 each time. Real order numbers come from the database.

self versus static

self:: always means "the class where this code is written". static:: means "the class the method was actually called on", which differs when a child class inherits the method. This is called late static binding:

php
<?php
class Model
{
    public static function create(): static
    {
        return new static();
    }

    public static function describeSelf(): string
    {
        return self::class;
    }

    public static function describeStatic(): string
    {
        return static::class;
    }
}

class User extends Model {}

echo get_class(User::create()) . "\n";
echo User::describeSelf() . "\n";
echo User::describeStatic() . "\n";
result
User
Model
User

User::create() built a User, not a Model, because of new static(). This is how framework base classes let User::create() and Product::create() share one implementation. ClassName::class gives the full name of a class as a string.

Common mistakes

  • Using $this in a static method, which is an error.
  • Forgetting the $ on static properties (self::$count) or adding one to constants (self::RATE).
  • Using static properties as shared mutable state that many parts of the code change.
  • Making everything static to avoid creating objects, which loses the benefits of objects and makes testing hard.

Exercise

Write a class Temperature with a private constructor that stores Celsius, and two named constructors fromCelsius(float $c) and fromFahrenheit(float $f). Add a method celsius(): float. Create 212 °F and 37 °C and print both in Celsius.

Show one possible answer
php
<?php
final class Temperature
{
    private function __construct(private float $celsius) {}

    public static function fromCelsius(float $c): self
    {
        return new self($c);
    }

    public static function fromFahrenheit(float $f): self
    {
        return new self(($f - 32) * 5 / 9);
    }

    public function celsius(): float
    {
        return round($this->celsius, 1);
    }
}

echo Temperature::fromFahrenheit(212)->celsius() . "\n";
echo Temperature::fromCelsius(37)->celsius() . "\n";
result
100
37

Key points

  • Static members belong to the class itself, not to one object, and are reached with ClassName::member.
  • Class constants (const VAT_RATE = 0.18;) hold fixed values; inside the class use self::VAT_RATE.
  • Named constructors such as Money::fromRupees(89.5) are static methods that create objects in a clear way.
  • static:: refers to the class that was actually called (late static binding); self:: always means the class where the code is written.

Check yourself

1. How do you call a static method fromRupees on the class Money?
2. Can a static method use $this?
3. What is the difference between self::create() and static::create() in a parent class?
4. Why are static properties used as global state considered risky?