覆盖特质方法时检测递归

时间:2018-08-13 13:22:44

标签: php laravel traits

两个库在trait中分别提供一个方法,该方法可以覆盖默认的基类方法。

// 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);
  }
}

现在,我的应用程序中有一个继承自Model的类,需要同时使用这两个特征。

PHP允许别名特征函数,以解决库之间的命名冲突。所以这就是我的最终目的:

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;
  }
}

我们最终遇到了递归问题:调用覆盖的trait方法时,它们引用parent::getAttribute方法,该方法触发另一个对Product::getAttribute的调用,该调用无限递归。

如何通过保留对两个特征的访问来解决此递归问题?

当然,由于每个特征都来自库,因此我无法更改其代码。

1 个答案:

答案 0 :(得分:2)

您可以利用private关键字将这些内容设为私有。

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;
  }
}

希望这会有所帮助。