doctrine/orm · error · LogicException
Doctrine ORM does not support property hook on %s::%s withou
Error message
Doctrine ORM does not support property hook on %s::%s without using native lazy objects. Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.
What it means
Doctrine's reflection-based lazy ghosts/proxies cannot intercept PHP 8.4 property hooks. When ProxyFactory builds a proxy (on first lazy load or getReference()) it walks every property of the class, and on PHP >= 8.4 any property with hooks makes it throw immediately — unless native lazy objects are enabled, which use the engine's lazy-object mechanism that supports hooks. Tracked in issue #11624.
Source
Thrown at src/Proxy/ProxyFactory.php:341
return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . InternalProxy::MARKER
. str_replace('\\', '', $className) . '.php';
}
private function getProxyFactory(string $className): Closure
{
$skippedProperties = [];
$class = $this->em->getClassMetadata($className);
$identifiers = array_flip($class->getIdentifierFieldNames());
$filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE;
$reflector = $class->getReflectionClass();
while ($reflector) {
foreach ($reflector->getProperties($filter) as $property) {
$name = $property->name;
if (PHP_VERSION_ID >= 80400 && count($property->getHooks()) > 0) {
throw new LogicException(sprintf(
'Doctrine ORM does not support property hook on %s::%s without using native lazy objects. Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.',
$property->getDeclaringClass()->getName(),
$property->getName(),
));
}
if ($property->isStatic() || ! isset($identifiers[$name])) {
continue;
}
$prefix = $property->isPrivate() ? "\0" . $property->class . "\0" : ($property->isProtected() ? "\0*\0" : '');
$skippedProperties[$prefix . $name] = true;
}
$filter = ReflectionProperty::IS_PRIVATE;
$reflector = $reflector->getParentClass();
}View on GitHub (pinned to d9b9ff7301)
Solutions
- Enable native lazy objects: $config->enableNativeLazyObjects(true) (requires doctrine/orm >= 3.3 with PHP >= 8.4)
- Remove property hooks from proxied entity classes
- Upgrade doctrine/orm to a release supporting property hooks (see issue #11624) and follow its upgrade notes
Example fix
// before (PHP 8.4, no native lazy objects)
public string $name {
set (string $value) { $this->name = trim($value); }
}
// $em->getReference(User::class, 1) throws
// after
$config = ORMSetup::createAttributeMetadataConfiguration([...], true);
$config->enableNativeLazyObjects(true); Defensive patterns
Strategy: validation
Validate before calling
if (PHP_VERSION_ID >= 80400) {
foreach ((new ReflectionClass($entityClass))->getProperties() as $prop) {
if (count($prop->getHooks()) > 0 && ! $config->isNativeLazyObjectsEnabled()) {
throw new RuntimeException('Enable native lazy objects or remove hooks on ' . $entityClass);
}
}
} Type guard
function entityHasPropertyHooks(string $class): bool
{
if (PHP_VERSION_ID < 80400) { return false; }
foreach ((new ReflectionClass($class))->getProperties() as $p) {
if (count($p->getHooks()) > 0) { return true; }
}
return false;
} Prevention
- Enable native lazy objects when adopting PHP 8.4 property hooks on entities
- Add a CI check on PHP 8.4 that loads one proxy per entity
- Keep hooked properties out of entities until the ORM version supports them
When it happens
Trigger: PHP >= 8.4, an entity (or its parent classes) declares a property with a get/set hook, and a proxy gets created for it — e.g., $em->getReference(User::class, $id) or accessing a lazy to-one association — while native lazy objects are NOT enabled via Configuration::enableNativeLazyObjects(true) (ORM 3.3+).
Common situations: Upgrading PHP to 8.4 and adopting property hooks (virtual hooks, `set` validation) on entities with existing lazy associations; new projects on 8.4 using hooks before enabling the ORM's native lazy object support.
Related errors
- The class "%s" is not part of the proxy namespace "%s"
- Lazy loading proxies require PHP 8.4 or higher.
- Proxy directory cannot be null
- Proxies destination directory '<info>%s</info>' does not exi
- Proxies destination directory '<info>%s</info>' does not hav
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/8aaf7fb693f006e9.
Report an issue: GitHub.