Description
Hey,
Thanks for these great packages.
I found something to what might be seen as a bug when registering the hooks in eloquence-metable
.
when working with the following structure:
abstract class Base {
use Metable;
}
class ChildA {
}
class ChildB {
}
class ChildC {
}
while instantiating the child classes, each of 'm runs bootMetable. Which ofcourse makes sense given Laravel's bootTraits nature.
The problem arises in sofa/hookable/src/Hookable.php:27
public static function hook($method, Closure $hook)
{
static::$hooks[$method][] = $hook;
}
since the hooks are stored in a static $hooks
property on the Base
class, each child class shares the same property.
When instantiating 3 childclasses, all 3 childclasses will register the hooks in it's base class. Effectively duplicating the code which needs to run.
In our case, we had 200 child classes, so 200 hooks were registered in the base class. When retrieving a property, and thus running through the registered hooks of getAttribute
, this caused quite a bit of performance loss and also a stack trace too deep.
I've fixed in on our side via:
use Sofa\Eloquence\Metable as MetableBase;
class Base {
use MetableBase {
MetableBase::bootMetable as metableBootMetable;
}
/** @var bool */
private static $isMetableBooted = false;
public static function bootMetable(): void
{
if (self::$isMetableBooted) {
return;
}
self::$isMetableBooted = true;
static::metableBootMetable();
}
but it might be worthwhile to backport that fix it here
Regards,