objects namespaces and application architecture

Static Members

Static methods are useful for named constructors, small stateless helpers, and class-level facts. Static properties are shared state, so use them carefully. Shared mutable state can make tests, long-running workers, and debugging harder.

Static Methods Do Not Need An Object

A static method can be called without creating an object.

PHP example
<?php

declare(strict_types=1);

class Slug
{
    public static function fromTitle(string $title): string
    {
        return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($title)) ?? '', '-');
    }
}

echo Slug::fromTitle('New Product Launch!') . PHP_EOL;

// Prints:
// new-product-launch

This works because the method does not need object state. It only depends on the input argument.

Static Methods Cannot Use $this

$this refers to a specific object. Static methods are not called on a specific object, so $this is not available.

PHP example
<?php

declare(strict_types=1);

class Vat
{
    public static function addStandardRate(int $netPennies): int
    {
        return (int) round($netPennies * 1.2);
    }
}

echo Vat::addStandardRate(1000) . PHP_EOL;

// Prints:
// 1200

If a method needs $this, it should usually be an instance method.

Static Named Constructors Can Improve Clarity

A static method can create an object in a named way.

PHP example
<?php

declare(strict_types=1);

class Money
{
    public function __construct(private int $pennies)
    {
    }

    public static function fromPounds(int $pounds): self
    {
        return new self($pounds * 100);
    }

    public function pennies(): int
    {
        return $this->pennies;
    }
}

$money = Money::fromPounds(25);

echo $money->pennies() . PHP_EOL;

// Prints:
// 2500

Money::fromPounds(25) communicates the input unit better than new Money(2500).

Static Properties Are Shared

A static property has one value for the class, not one value per object.

PHP example
<?php

declare(strict_types=1);

class IdSequence
{
    private static int $nextId = 1;

    public static function next(): int
    {
        return self::$nextId++;
    }
}

echo IdSequence::next() . PHP_EOL;
echo IdSequence::next() . PHP_EOL;

// Prints:
// 1
// 2

This can be useful in tiny examples, but real applications usually get IDs from databases, UUID generators, or dedicated services.

Avoid Static Service Locators

Static access can hide dependencies. Code that calls Database::query() from anywhere is harder to test and reason about than code that receives a database connection or repository explicitly.

PHP example
<?php

declare(strict_types=1);

class ReferenceGenerator
{
    public static function orderReference(int $id): string
    {
        return 'ORD-' . str_pad((string) $id, 6, '0', STR_PAD_LEFT);
    }
}

echo ReferenceGenerator::orderReference(42) . PHP_EOL;

// Prints:
// ORD-000042

This static method is fine because it is deterministic and has no hidden external dependency.

Use self:: Inside The Same Class

Inside a class, use self:: to refer to static members on that class.

PHP example
<?php

declare(strict_types=1);

class OrderStatus
{
    private static array $paidStatuses = ['paid', 'settled'];

    public static function isPaid(string $status): bool
    {
        return in_array($status, self::$paidStatuses, true);
    }
}

echo OrderStatus::isPaid('paid') ? 'paid' : 'unpaid';
echo PHP_EOL;

// Prints:
// paid

Later lessons cover static:: and late static binding. For now, self:: is the direct way to refer to the current class.

What To Remember

Use static methods for stateless helpers, named constructors, and class-level facts. Be cautious with static properties because they are shared mutable state. If code needs configuration, a database, a clock, a logger, or an API client, passing a dependency is usually clearer than hiding it behind static access.

Practice

Task: Create Order References

Create a small class for generating order references.

Requirements

  • Use declare(strict_types=1);.
  • Create an OrderReference class.
  • Add a static method that accepts a positive integer order ID.
  • Reject IDs lower than 1.
  • Return references in the format ORD-000123.
  • Print two valid references.
  • Show one invalid ID by catching the exception.
  • Include the expected output as comments in the same PHP code block.

The method should be static because it is deterministic and does not need object state.

Show solution
PHP example
<?php

declare(strict_types=1);

class OrderReference
{
    public static function fromId(int $id): string
    {
        if ($id < 1) {
            throw new InvalidArgumentException('Order ID must be positive.');
        }

        return 'ORD-' . str_pad((string) $id, 6, '0', STR_PAD_LEFT);
    }
}

echo OrderReference::fromId(42) . PHP_EOL;
echo OrderReference::fromId(123) . PHP_EOL;

try {
    OrderReference::fromId(0);
} catch (InvalidArgumentException $exception) {
    echo $exception->getMessage() . PHP_EOL;
}

// Prints:
// ORD-000042
// ORD-000123
// Order ID must be positive.

The method is static because it only transforms an input value into a reference string. It has no object state and no hidden external dependency.