A PHP static method belongs to a class definition itself and can be called directly with ClassName::method() without creating an object via new. Static methods work cleanly for stateless utilities and named factory constructors, though overusing them makes application code harder to mock in tests.
::Inside a static method, $this is unavailable because no object instance exists. Instead, use self:: to call another static member on the same class, or static:: for late static binding in subclasses.
<?php
declare(strict_types=1);
class SlugHelper
{
public static function fromTitle(string $title): string
{
$slug = strtolower(trim($title));
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug) ?? '';
return trim($slug, '-');
}
}
echo SlugHelper::fromTitle('PHP Static Methods Guide!') . PHP_EOL;
One of the cleanest patterns in PHP OOP is pairing a private __construct() with readable static factory methods like Money::fromCents(1999) or DateRange::forLastDays(7). Named constructors make object creation self-documenting and keep validation localized.
<?php
declare(strict_types=1);
final class Money
{
private function __construct(public readonly int $cents, public readonly string $currency) {}
public static function fromDollars(float $dollars, string $currency = 'USD'): self
{
return new self((int) round($dollars * 100), $currency);
}
}
$price = Money::fromDollars(24.99);
echo "{$price->currency} {$price->cents} cents" . PHP_EOL;
$this inside a static method: PHP throws an Error: Using $this when not in object context. Static methods can only touch parameters and self::/static:: members.UserService::find(1) inside controllers makes swapping dependencies during automated tests difficult. Prefer injected instance services for I/O work.ClassName::method() throws a fatal Error.self:: and static::?self:: binds at compile time to the class where the method is defined. static:: (late static binding) resolves to the subclass that actually called the method at runtime.
Use static methods for pure stateless conversions (like SlugHelper::fromTitle()) or named constructors (Money::fromDollars()). Use instance methods when the method depends on injected services or object state.
private or protected?Yes. private static helpers are great for organizing internal parsing steps inside a class without exposing them publicly.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.