覆盖特征方法时检测递归

Detect recursion when overridding trait methods

两个库分别提供了一个特性,一种覆盖默认基础 class 方法的方法。

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

现在,我的应用程序中有一个 class 继承自 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;
  }
}

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

我们如何通过保持对两个特征特征的访问来解决这个递归问题?

当然,由于每个特征都来自一个库,我无法更改它们的代码。

您可以利用 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;
  }
}

希望对您有所帮助。