【问题标题】:Cannot do OOP Callback function for usort无法为 usort 执行 OOP 回调函数
【发布时间】:2015-06-26 22:31:20
【问题描述】:

我已经阅读了几十篇关于将类成员用作回调函数的讨论,但没有一个示例涉及在我看来是显而易见的 OOP 设计,它是基于与 C++ 和 Java 等其他 OOP 语言一起使用的。

我在类中定义了一个比较方法:

class TestClass {
private $aField; // integer value
function _construct($value)
{
        $this->aField   = $value;
}       // TestClass::_construct

function compare($other)
{
    if ($other instanceof TestClass)
    {           // comparing two instances
    return $this->afield - $other->afield;
    }           // comparing two events
    else
    throw new Exception("parameter is not instance of TestClass");
}       // TestClass::compare
}       // class TestClass

$instances  = array(new TestClass(5),new TestClass(3));
// the following fails because:
// 1. $this is not defined outside a class member
// 2. compare does not take two parameters
usort($instances, array($this, 'compare'));

// the following kluge works around this
function order($this, $that) { return $this->compare($that); }
usort($instances, 'order');

我可以在这个论坛和 PHP 文档中找到的所有示例都不完整,因为它们没有显示调用 usort 的上下文。现在我可以通过使比较函数成为具有两个参数的静态函数并将其作为可调用数组('TestClass','compare')调用来解决这个问题,但是将比较方法定义为的静态函数并不直观班上。基于 30 多年的 OOP 静态函数的个人经验,在大多数情况下是糟糕的类设计的结果。尤其是静态方法会破坏多态性。

我正在寻找的是一个类似于 Java 的排序函数,它利用了 Comparable 接口。我看到早在 2010 年就有一些关于定义 Comparable 接口的讨论,但该讨论仅与比较运算符有关,并且使 PHP 纯粹主义者感到不舒服,因为它重载了运算符。然而,Java Comparable 接口 重载运算符,因为除了 String 类的明显例外,Java 不支持重载运算符。在 Java 中实现 Comparable 接口使您可以使用 SortedMaps 中的类并对 Collection 中的实例进行排序,但是如果您希望比较两个对象,则必须显式调用 compareTo 方法。我还看到有一个基本上未记录的 compare_objects 方法,它已经覆盖了比较运算符的默认实现。换句话说,尽管有纯粹主义者的反对,PHP 已经允许您为一个类重载比较运算符。但是,当要求对对象进行排序时,PHP 排序函数是否使用 compare_objects 没有记录。

【问题讨论】:

标签: php oop


【解决方案1】:

你在课堂外调用 $this。

$obj = new TestClass();
$sorted = usort($instances, array($obj, 'compare'));

你也可以这样做(没有测试代码)

class TestClass() {
    function compareWith($other) {
        $arr = array($this, $other);
        usort($arr, function($that, $other) {
            if ($other instanceof TestClass)
            {           // comparing two instances
            return $other->afield - $that->afield;
            }           // comparing two events
            else
                throw new Exception("parameter is not instance of TestClass");
        });
        return $arr;
    }
}

$instance1  = new TestClass();
$instance2  = new TestClass();
$sorted = $instance1->compareWith($instance2);

【讨论】:

  • 在真正的 OOP 中,例如 Java,排序函数是集合类的方法,而不是单个对象的方法。在 PHP 中,各种类型的排序都是全局函数。
【解决方案2】:

您在您的 cmets 中提到了一个集合类 - 所以这里有一个使用(非常基本的)集合类的示例,并结合了我提到的手册中用户评论中的排序方法:

class Collection {
  private $itemType;
  private $items;

  public function __construct($itemType) {
    $this->itemType = $itemType;
    $this->items = [];
  }

  public function add($item) {
    if($item instanceof $this->itemType) {
      $this->items[] = $item;
    }
    else {
      throw new Exception('Only items of Type ' . $this->itemType . ' can be added!');
    }
  }

  public function sort() {
    usort($this->items, array($this, 'compareItems'));

    var_dump($this->items); // test output, to check the result
  }

  private function compareItems($a, $b) { // calls the compare method of the item class
    return $a->compare($b);
  }
}


class TestClass {
  private $aField;

  public function __construct($value) {
    $this->aField = $value;
  }

  public function compare($other) {
    if($other instanceof TestClass) {
      return $this->aField - $other->aField;
    }
    else {
      throw new Exception('Parameter is not instance of TestClass!');
    }
  }
}

$collection = new Collection('TestClass');

$collection->add(new TestClass(5));
$collection->add(new TestClass(1));
$collection->add(new TestClass(3));

$collection->sort();

【讨论】:

    猜你喜欢
    • 2010-11-08
    • 2013-05-11
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多