【问题标题】:PHP classes: ArrayAccess interface - Is it possible to use the array interface directly in a class?PHP 类:ArrayAccess 接口 - 是否可以直接在类中使用数组接口?
【发布时间】:2014-03-01 03:12:16
【问题描述】:

在 PHP 中,我尝试直接访问类成员(使用 ArrayAccess 接口),而无需创建新实例。

例如:

class my_class implements ArrayAccess {
    private static $d=array();
    function offsetGet($o){return self::$d[$o];}
    function offsetSet($o,$v){self::$d[$o]=$v;}
}
my_class['foo']='bar';//Syntax error
echo my_class['foo'];

我只想知道是否有任何方法可以让这种情况发生而不必这样做$var=new my_class();

我不想这样做,除非它是非常必要的并且没有办法解决该语法错误。

如果可能的话,我想摆脱那个语法错误。

我不能 100% 确定这是否可能(可能不会),但总比在怀疑中死去而不去尝试更好。

我在 Windows 8 Pro x64 上使用 PHP 5.4.7,在英特尔 core2quad i586 2.63ghz 上运行(以防万一)。

【问题讨论】:

  • 为什么不能只使用数组?
  • 因为我想做其他任务,比如运行函数和添加 getter 和 setter。此外,我想保持一切静态,而不是简单地获取或设置父静态类的值的实例。然后我将不得不在同一个类中创建具有相同名称的静态和非静态成员,这是不可能的而且是荒谬的。
  • “那么我将不得不在同一个类中创建具有相同名称的静态和非静态成员”。为此创建一个基于“包”的方法是常见的做法。基本上,您有一个可以实例化并表示一个对象(来自商店或其他方式)的类,然后您有一个能够操作多个对象的类。在学说中,这些被称为 Table 类,在 Propel 中被称为对等类。使用这种方法,您可以通过将成员变量附加到实际对象或“包”类来分隔成员变量。
  • 我不想要那个。我想将类用作变量和数组。就像你怎么做$foo['bar'],我想做my_class['foo']。另外,我有一个setter的方法,我相信不可能做到$class=new my_class(); $class->setter($param);my_class::setter($param);
  • 您是否研究过魔术 getter/setter? php.net/manual/en/language.oop5.overloading.php#object.get

标签: php class static-methods static-members arrayaccess


【解决方案1】:

好吧,我知道这是不可能的,所以,我真的不得不使用新的实例。

结果如下:

error_reporting(E_ALL^E_STRICT);//removes the "Strict Standards" warning, don't do this
final class session implements ArrayAccess {
    //session data
    private static $s=null;

    //function (setters and getters)
    private static $f=array('s'=>array(),'g'=>array());//general setter/getter
    private $c=array('s'=>array(),'g'=>array());//private setter/getter

    function setter($k,$f=null)
    {
        if(($a=func_num_args())<=1)return!$a?false:((@$this)?(@$this->c['s'][$k]):(@self::$f['s'][$k]));
        else if($f==null){if(@$this)unset($this->c['s'][$k]);else unset(self::$f['s'][$k]);return true;}
        else return is_callable($f)&&(@$this?$this->c['s'][$k]=$f:self::$f['s'][$k]=$f);
    }

    function getter($k,$f=null)
    {
        if(($a=func_num_args())<=1)return!$a?false:((@$this)?(@$this->c['g'][$k]):(@self::$f['g'][$k]));
        else if($f==null){if(@$this)unset($this->c['g'][$k]);else unset(self::$f['g'][$k]);return true;}
        else return is_callable($f)&&(@$this?$this->c['g'][$k]=$f:self::$f['g'][$k]=$f);
    }

    //==== arrayaccess ====
    //extra: setters and getters implemented when accessing $session['offset']
    //       setter: gives the value, expects a value in return
    //       getter: gives the value, returns the value returned by the getter
    function offsetSet($o,$v){@self::$s[$o]=(@$this->c['s'][$o])?$this->c['s'][$o]($v,$o):(@self::$f['s'][$o]?call_user_func(self::$f['s'][$o],$v,$o):@self::$s[$o]);}
    function offsetExists($o){return isset(self::$s[$o]);}
    function offsetUnset($o){unset(self::$s[$o]);}
    function offsetGet($o){return(@$this->c['g'][$o])?$this->c['g'][$o](@self::$s[$o]):(@self::$f['g'][$o]?call_user_func(self::$f['g'][$o],@self::$s[$o]):@self::$s[$o]);}
    //==== arrayaccess ====
}

$s=new session();

$s->setter('test',function($ob){return$ob>6?'bigger than 6':'lower than 6';});

session::setter('test',function($st){return$st<5?'lower than 5':'bigger than 5';});
session::setter('test',null);//*deletes the setter,*/ session::setter('test');//return setter

$s['test']=5;

var_dump($s->setter('test'),session::setter('test'),$s['test']);
//expected output (php 5.3.0): object(Closure)#2 (1) { ["parameter"]=> array(1) { ["$ob"]=> string(10) "" } } NULL string(12) "lower than 6"

我知道它看起来很糟糕,但按预期工作!

所有数据都在所有新实例之间共享,一般上下文中的所有设置器都按预期执行。

如果您想为自己使用此代码,请记住:

  • session::[sg]etter('test',null);session::[sg]etter('test'); 不同!

  • setter有2个参数(value和offset),而getter只有1个(value);

  • setter 和 getter 都必须返回一个值!

在其中一个 cmets 中我是这样说的:

我有一个setter方法,我相信不可能做到 $class=new my_class(); $class->setter($param);和 my_class::setter($param);

嗯,这不是不可能的,它只是不标准(这就是为什么第一行是error_reporting(E_ALL^E_STRICT);)。如果没有这一行,当您尝试执行 session::setter('test'); 时,PHP 会发疯。

【讨论】:

  • 《侏罗纪公园》第一部有一句名言:“你忙着担心自己能不能做,却没有停下来思考是否应该做。”您必须放宽严格的标准以避免 php 发疯这一事实应该是一个危险信号,表明这不是正确的方法。从可维护性的角度来看,这段代码不仅是一场灾难,你甚至对它进行了分析吗?我很好奇所有这些匿名函数调用是否比调用具体函数更快、相同或更慢。
  • 我不担心超快或任何东西。我只是希望它易于使用,而不是简单地制作和运行。老实说,它们已尽可能优化(除了到处都有错误抑制 (@) 指令,而不是使用 isset())。我已经提到严格的警告是当我访问session::[gs]etter() 而不是session-&gt;[gs]etter()
猜你喜欢
  • 2012-07-05
  • 2020-10-31
  • 1970-01-01
  • 2011-05-18
  • 2015-02-23
  • 1970-01-01
  • 2018-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多