【问题标题】:Is it possible to overload operators in PHP?是否可以在 PHP 中重载运算符?
【发布时间】:2010-10-21 17:20:37
【问题描述】:

具体来说,我想创建一个 Array 类并想重载 [] 运算符。

【问题讨论】:

    标签: php operator-overloading


    【解决方案1】:

    如果您使用的是 PHP5(并且应该使用),请查看 SPL ArrayObject 类。文档不太好,但我认为如果你扩展 ArrayObject,你就会有你的“假”数组。

    编辑:这是我的简单示例;不过,恐怕我没有有价值的用例:

    class a extends ArrayObject {
        public function offsetSet($i, $v) {
            echo 'appending ' . $v;
            parent::offsetSet($i, $v);
        }
    }
    
    $a = new a;
    $a[] = 1;
    

    【讨论】:

    • 不仅是一个有用的答案,而且是正确的答案。我一直在使用 ArrayObjects,它是一种优雅的方式,不仅可以覆盖数组,而且可以扩展整个对象模型并使 PHP 踢出一些严肃的事情。
    • 不是一个有用的答案或正确的答案。问题是关于运算符重载,而不是是否存在带有名为 ArrayObject 的对象的库。
    • -1 使用 ArrayAccess 接口。不要扩展 ArrayObject。你继承了很多你可能不需要的逻辑,而且 ArrayObject 的扩展在很多方面都是不可预测的,因为其中涉及到很多魔法。
    • NikkiC,你的答案可能好多了,你不应该把它添加为真正的答案吗?
    • 特别值得注意的是,如果您需要一个数组而不是哈希表,您可以使用 SplFixedArray 为您提供更快的数组功能 - 重载它,添加一个私有 array(),并使用 is_numeric 来决定在哪里存储数据;将为您提供大型数组的巨大速度提升 - 不知道为什么 php 默认不这样做!
    【解决方案2】:

    其实最优方案是实现ArrayAccess接口的四个方法: http://php.net/manual/en/class.arrayaccess.php

    如果您还想在“foreach”的上下文中使用您的对象,则必须实现“Iterator”接口: http://www.php.net/manual/en/class.iterator.php

    【讨论】:

    • +1。实现 ArrayAccess 接口是对 OP 问题的唯一有效答案。所有其他都不是最理想的。
    【解决方案3】:

    PHP 的重载和运算符概念(参见OverloadingArray Operators)与C++ 的概念不同。我认为不可能重载 +、-、[] 等运算符。

    可能的解决方案

    【讨论】:

    • 比迭代器更好的是 SPL ArrayObject,我在下面链接到它。它提供了所有数组功能。
    【解决方案4】:

    对于 PHP 5.0+ 中的简单而干净的解决方案,您需要实现 ArrayAccess interface 并覆盖函数 offsetGet、offsetSet、offsetExists 和 offsetUnset。您现在可以像使用数组一样使用对象了。

    示例(PHP7+):

    <?php
    class A implements ArrayAccess {
        private $data = [];
    
        public function offsetGet($offset) {
            return $this->data[$offset] ?? null;
        }
    
        public function offsetSet($offset, $value) {
            if ($offset === null) {
                $this->data[] = $value;
            } else {
                $this->data[$offset] = $value;
            }
        }
    
        public function offsetExists($offset) {
            return isset($this->data[$offset]);
        }
    
        public function offsetUnset($offset) {
            unset($this->data[$offset]);
        }
    }
    
    $obj = new A();
    $obj[] = 'a';
    $obj['k'] = 'b';
    echo $obj[0], $obj['k']; // print "ab"
    

    【讨论】:

    • 这是关于 OP 问题的最佳(最准确)答案。如果您只是想在对象上使用[] 运算符,那么实现ArrayAccess 接口是可行的方法。
    【解决方案5】:

    这似乎不是该语言的特性,请参阅此bug。但是,看起来有一个package 可以让您进行某种重载。

    【讨论】:

    • 看包,好像不兼容任何php > 5.5,从2013年开始就没更新过
    • 这个答案已经过时了。
    【解决方案6】:

    简单地说,不;我建议如果你认为你需要 C++ 风格的重载,你可能需要重新考虑你的问题的解决方案。或者也许考虑不使用 PHP。

    套用 Jamie Zawinski 的话说,“你有一个问题并想,'我知道!我将使用运算符重载!'现在你有两个问题。”

    【讨论】:

    • -1 答案是完全不正确的,因为有可能重载 [] 运算符。此外,@Chad 很可能不是试图解决运算符重载的问题,而是保持他的代码简洁明了。
    • 需要重新考虑我的设计吗?所以如果我想做复杂的算术或广泛的日期算术,我必须使用函数调用而不是运算符?糟糕。
    • 我认为日期运算不能清晰地映射到普通算术运算符。你可能会说,“好吧,当我在日期操作中使用 + 号时,它并不意味着加法,它意味着类似但略有不同的东西”,我会说使用普遍理解的运算符来处理不同于什么的东西该运算符用于主要会导致混乱和悲伤。
    • @dirtside 按照这个逻辑,我们应该对整数和浮点数进行不同的操作。 (某些语言,如 OCaml IIRC,确实有这个,例如 + 用于整数加法和 +. 用于浮点加法。)我猜你会说这是一个痛苦的脖子,但它只是表明你有一个权衡'在那里也重新制作,不同的人只是在不同程度上做到这一点。放下你的一派胡言 :-) 为不同的目的使用相同的运算符不是异端,而是实用的。 (参数列表的括号运算符优先级?!这就是疯狂!)
    • @dirtside 整数和浮点数在计算机上的算术运算下表现相同!对于初学者来说,3 / 2 与 3.0 / 2.0 不同 - 同样,许多属性在一种类型中不与另一种类型相同。我的观点不是日期算术是 100% 的好主意。只是您应该意识到,您可能会做出与您争论的相同的权衡,只是使用其他数据类型。你可以挥挥手说“好吧,整数和浮点数大致相同”,我也可以对数字和日期做同样的事情(它们只是从 Epoch 开始的整数秒,对吧?)
    猜你喜欢
    • 2015-01-01
    • 2012-09-04
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 2012-01-12
    • 2017-05-06
    • 2023-04-05
    相关资源
    最近更新 更多