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
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
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
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
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
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
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
OrderReferenceclass. - 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
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.