Reputation: 28541
Two libraries provide each inside a trait, a method to override a default base class method.
// This is a Framework base class
class Model {
function getAttribute($key) {
return "Model->$key";
}
}
// This is a trait from library A which provides extra stuff
trait HasUuid {
function getAttribute($key) {
if ($key==='uuid') return "HasUuid->$key";
return parent::getAttribute($key);
}
}
// This is a trait from library B which provides extra stuff
trait HasQuantity {
function getAttribute($key) {
if ($key==='quantity') return "HasQuantity->$key";
return parent::getAttribute($key);
}
}
Now, I have a class in my application which inherits from Model
and needs to use both traits.
PHP allows to alias the trait functions in order to resolve naming conflicts between libraries. So here is what I end up with:
class Product extends Model {
use HasUuid { getAttribute as getHasUuidAttribute; }
use HasQuantity { getAttribute as getHasQuantityAttribute; }
function getAttribute($key) {
// Framework default value to use as fallback
$parentValue = parent::getAttribute($key);
$overrides = ['getHasUuidAttribute', 'getHasQuantityAttribute',];
foreach ($overrides as $override)
{
$overriddenValue = $this->$override($key);
// A trait has some better value than the fallback
if ($overriddenValue !== $parentValue) return $overriddenValue;
}
// Nothing better, use fallback from framework
return $parentValue;
}
}
We end up with a recursion issue: when calling the overridden trait methods, their refer to the parent::getAttribute
method which triggers another call to Product::getAttribute
which recurses infinitly.
How can we solve this recursion issue, by keeping access to both trait features?
Of course, as the traits each come from a library, I cannot change their code.
Upvotes: 3
Views: 304
Reputation: 15951
You can take advantage of making these private using a private
keyword.
class Product extends Model {
use HasUuid { getAttribute as private getHasUuidAttribute; }
use HasQuantity { getAttribute as private getHasQuantityAttribute; }
function getAttribute($key) {
// Framework default value to use as fallback
$parentValue = parent::getAttribute($key);
$overrides = ['getHasUuidAttribute', 'getHasQuantityAttribute',];
foreach ($overrides as $override)
{
$overriddenValue = $this->$override($key);
// A trait has some better value than the fallback
if ($overriddenValue !== $parentValue) return $overriddenValue;
}
// Nothing better, use fallback from framework
return $parentValue;
}
}
Hope this helps.
Upvotes: 2