【问题标题】:Emulating a value type structure class in PHP在 PHP 中模拟值类型结构类
【发布时间】:2010-12-01 23:40:18
【问题描述】:

有没有办法在 PHP 中模拟结构类?即一个通过值而不是通过引用传递的类,所以它仍然可以被类型提示......

如果是这样,可以使用哪些不同的技术?最好的技术是什么?

如果可能的话,您显然可以为 PHP 创建一个完全类型安全的层,有这样的层吗?有没有人有这方面的经验?

【问题讨论】:

    标签: php types structure type-safety


    【解决方案1】:

    我认为最简单的方法是像 java 那样做——让你的值类是不可变的,并让所有“修改”方法返回一个新对象。

    【讨论】:

    • 如果你将它传递给一个函数,你如何确保它传递的是副本而不是引用?还是每次要传递时都必须使用克隆运算符?
    • 它会传递一个引用,但这并不重要——接收函数无论如何也无法修改它。换句话说,只要对象是不可变的,复制和引用的区别就消失了。
    【解决方案2】:

    我认为你无法实现这个目标,只有使用 PHP 代码。

    您无法控制 PHP 函数如何处理参数,我看不出您如何确保一切都按照您想要的方式处理,而无需更改 PHP 二进制文件和模块中的(低级)代码.

    不过会很酷:)

    【讨论】:

      【解决方案3】:

      对象总是通过引用传递。使它们作为副本传递的唯一方法是显式使用 clone 关键字(是的,无处不在)。

      我的建议是使用数组,它是值类型,因此总是被复制。由于您可以将其用作关联数组(例如字符串 -> 值),因此它也可以是一个对象。当然,缺点是你不能使用方法(但这就像一个结构,所以你可能会对此感到满意)。然而,没有办法强制执行类型安全。

      但是说实话,根据您的所有要求,PHP 不是您喜欢的语言。

      【讨论】:

      • 把它放在一个数组中可能是合理的,但是你不能再打字了......好吧你可以打字一个数组,但这不再是类型安全的......恶性循环......我'使用 php 已经有很长一段时间了,越来越多的我开始怀念类型安全之类的东西......
      【解决方案4】:

      我正在玩弄匿名的建议,让对象的任何突变都返回一个新对象,这可行,但很尴尬。

      <?php
      class FruityEnum {
          private $valid = array("apple", "banana", "cantaloupe");
          private $value;
      
          function __construct($val) {
              if (in_array($val, $this->valid)) {
                  $this->value = $val;
              } else {
                  throw new Exception("Invalid value");
              }
          }
      
          function __set($var, $val) {
              throw new Exception("Use set()!!");
          }
          function set(FruityEnum &$obj, $val) {
              $obj = new FruityEnum($val);
          }
      
          function __get($var) { //everything returns the value...
              return $this->value;
          }
          function __toString() {
              return $this->value;
          }
      }
      

      现在来测试一下:

      function mutate(FruityEnum $obj) { // type hinting!
          $obj->set($obj, 'banana');
          return $obj;
      }
      
      $x = new FruityEnum('apple');
      echo $x; // "apple"
      $y = mutate($x);
      echo  $x // still "apple"
          . $y // "banana"
      

      可以,但是你必须使用一种奇怪的方式来改变对象:

      $obj->set($obj, 'foo');
      

      我能想到的唯一其他方法是使用__set() 方法,但那更糟。您必须这样做,这非常令人困惑。

      $obj = $obj->blah = 'foo';
      

      最后,将变量设为私有且不提供修改器可能更容易,因此更改变量“枚举”值的唯一方法是创建一个新变量:

      echo $obj; // "banana"
      $obj = new FruityEnum("cantaloupe");
      

      【讨论】:

      • 不错的实验,尽管它产生的开销与使用克隆运算符一样多。 +1
      猜你喜欢
      • 2019-08-25
      • 2017-10-21
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-23
      相关资源
      最近更新 更多