【问题标题】:unwanted method called [closed]不需要的方法称为[关闭]
【发布时间】:2012-10-18 03:37:26
【问题描述】:

让我们看一个基本类:

class A
{
   public function renderSomethingRecursive()
   {
      //this function can call itself
      self::renderSomethingRecursive(); // ERROR!!!!
   }

   abstract public function addSomething (value);
}

class B extends A
{
   public function renderSomethingRecursive()
   {
      throw new Exception ('This time this method must not be called!');
   }

   public function addSomething (value)
   {
      //something, something, something....
      parent::renderSomethingRecursive();
   }
}

$obj = new B();
$obj->addSomething(....);

当我这样做时,B::renderSomethingRecursive() 仍然会被调用,这是我不想要的……在A:renderSomethingRecursive() 方法上,在self::renderSomethingRecursive(); // ERROR!!!! 行调用B::renderSomethingRecursive(); 而不是 A::renderSomethingRecursive();,这是合理的,因为 $this 现在是 B 而不是 A... 但是我不知道如何躲避它。

顺便说一句,我知道 B::renderSomethingRecursive() 方法应该被删除,但我想保留它作为一个通知,它不能被意外调用。我想将其设为“私有”以使其不可用,但正如我们所知,这是不可能的:)

有什么想法吗?

【问题讨论】:

  • 无法重现——您的代码从不调用B::renderSomethingRecursive()(我只对其进行了足够的修改以使其运行,即删除value,将A声明为abstract等)。
  • 我也无法复制。你有什么问题?
  • 请贴出实际代码,由于语法错误,此代码无法运行。它不应该从 B 运行方法,所以你显然做错了什么,但没有用这段代码显示它。

标签: php oop polymorphism virtual-functions


【解决方案1】:

为什么不进行重构以支持组合而不是继承?如果您开始将“添加内容”和“递归内容”拆分为单独的关注点,您会发现自己拥有更小、更易于理解的类,它们可以很好地协同工作。

由于您不希望B 的调用者能够调用renderSomethingRecursive(),因此从类中完全删除该函数。还要打破继承,B不需要继承自A。 我们仍然希望B 能够“添加东西”,所以它会保留一个名为addSomething() 的函数。因为我们不想在两个类中复制addSomething 的主体,所以只要调用B::addSomething,我们就可以让B 委托给A 的一个实例。

abstract class A
{
   public function renderSomethingRecursive()
   {
      // this function can call itself
      self::renderSomethingRecursive();
   }

   abstract function addSomething ($value) {

}

class AA extends A
{
   public function addSomething($value)
   {
      // something, something, something....
      self::renderSomethingRecursive();
   }
}


class B
{
   private $a;
   public function __construct(A $a)
   {
      $this->a = $a;
   }

   public function addSomething ($value) {
      $this->a->addSomething($value);
   }
}

$obj = new B(new AA());
$obj->addSomething(....);

这已经变得更好了,但是我们可以在完成之前摆脱这个重复的addSomething。 渲染和管理列表实际上是两个不同的问题,所以让我们把它分开。首先,我们将addSomething 移动到B。然后我们意识到renderSomethingRecursive 可能也需要访问 $data,我们可以添加一些参数,以便它可以再次访问该数据。 A 不再需要抽象,但如果addSomething 仍有不同的实现,B 可能是抽象的。 你应该留下这样的东西......

class A
{
   public function renderSomethingRecursive($data)
   {
      // this function can call itself
      self::renderSomethingRecursive($data);
   }     
}

class B
{
   private $a;
   private $data;
   public function __construct(A $a)
   {
      $this->a = $a;
   }

   public function addSomething ($value) {
      // something, something, something....
      // append to $this->data probably
      $this->a->renderSomethingRecursive($this->data);
   }
}

$obj = new B(new AA());
$obj->addSomething(....);

【讨论】:

  • 这根本不是我们开始使用 OO 语言的原因。关键是尽可能避免这种结构,此外,A 是一个 abstract 类,它不能被实例化。还要记住,作为另一个对象属性的对象无权访问该对象的方法,反之亦然(无受保护的访问)。最后:如果您要创建一个方法,最好使用 类型提示 i>: public function __construct(A $a) 避免将错误的对象传递给构造函数
  • Elias,你在构造函数中省略类型提示是对的,我将更新我的示例以包含它。虽然我不同意避免这些类型的结构,但我认为太多的 OOP 程序员过于关注可扩展性而没有足够的组合;这是我们两种解决方案的主要区别。
  • 我正要修改我的代码...我再次启动它,代码完全不起作用
【解决方案2】:

如果您不想调用它,为什么还要在B 中定义该方法。只是不要定义它,PHP 只能调用 1 种方法。这样,您不必使用parent::theMethod,您可以轻松地使用this->theMethod(); 调用它

Abstract class A
{
   public function renderSomethingRecursive()
   {
      $this->renderSomethingRecursive(); // no need for self::, that's for static calls
   }

   abstract public function addSomething (value);
}

class B extends A
{
   public function addSomething (value)
   {
      $this->renderSomethingRecursive();//calls the abstract method as though it were defined in class B
   }
}

仅此而已

【讨论】:

    猜你喜欢
    • 2015-09-12
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    相关资源
    最近更新 更多