Metaclass¶
A metaclass is a class whose instances are themselves classes. In a language with a full metaclass system, every class is an object, and that object is an instance of a metaclass. The metaclass controls how the class is created, how its instances are instantiated, and how method resolution, attribute access, and inheritance work. Python’s type is the default metaclass; a custom metaclass inherits from type and overrides __new__, __init__, or __call__ to intercept class creation.
Smalltalk was the original language to formalise the idea: every class in Smalltalk has a corresponding metaclass that describes the class’s own behaviour. Ruby’s eigenclasses (singleton classes) serve a related role.
PHP does not have metaclasses. PHP classes are not objects that can be instantiated from a metaclass, and there is no hook point at which user code can intercept or modify class creation at the language level.
PHP approximations of metaclass-like behaviour:
Abstract classes and interfaces constrain what a class must look like without controlling how it is created.
The Reflection API (
ReflectionClass) allows runtime introspection of a class’s structure but cannot alter it.Magic methods
__get,__set,__call, and__callStaticintercept property and method access on instances, approximating some MOP hooks.Attribute-driven frameworks such as Doctrine or Symfony DI read class-level
#[Attribute]annotations and generate or register behaviour at build time, simulating what a metaclass might do during class creation in Python.class_alias()can create alternative names for classes but cannot redefine their behaviour.
<?php
// PHP has no metaclass. The Reflection API offers read-only introspection.
$rc = new ReflectionClass(DateTime::class);
echo $rc->getName() . ' has ' . count($rc->getMethods()) . " methods\n";
// Attribute-driven behaviour: closest PHP equivalent to metaclass registration.
#[\Attribute(\Attribute::TARGET_CLASS)]
final class Entity {
public function __construct(public readonly string $table) {}
}
#[Entity(table: 'users')]
class User {
public function __construct(
public readonly int $id,
public readonly string $name,
) {}
}
// A framework reads the attribute at build or boot time — similar to what
// a Python metaclass __init_subclass__ hook would do automatically.
$attr = (new ReflectionClass(User::class))
->getAttributes(Entity::class)[0]
->newInstance();
echo $attr->table; // 'users'
?>
See also PHP Reflection API and Python metaclasses.
Related : Meta-object Protocol, Metaprogramming, Reflection, Attribute, Magic Methods, Abstract Class, __call() Method