PHP可以剖析自己的语法吗?

时间:2010-05-03 14:40:36

标签: php

PHP可以解析自己的语法吗?例如,我想写一个函数,它接受像$object->attribute这样的输入并对自己说:

  

好的,他正在给我$foo->bar,这意味着他必须认为$foo是一个具有bar属性的对象。在我尝试访问bar并可能获得“尝试获取非对象属性”错误之前,让我检查$foo是否是对象。

最终目标是在设置值时回显值,如果不是则静默失败。

我想避免像这样重复:

<input value="<? if(is_object($foo) && is_set($foo->bar)){ echo $foo->bar; }?> "/>

...并且避免编写一个执行上述操作的函数,但必须单独传入对象和属性,如下所示:

<input value="<? echoAttribute($foo,'bar') ?>" />

...但而不是写下以下内容:

  • 保留object-&gt;属性语法
  • 非常灵活:还可以处理数组键或常规变量

像这样:

<input value="<? echoIfSet($foo->bar); ?> />
<input value="<? echoIfSet($baz['buzz']); ?> />
<input value="<? echoIfSet($moo); ?> />

但这一切都取决于PHP能够告诉我“当我说$object->attribute$array[$key]时,我要求的是什么样的东西,以便我的功能可以根据自己的要求处理每个类型。

这可能吗?

更新

我在这里得到了一些好的答案并做了一些实验。想总结一下。

  • 我原来问题的答案似乎是“不”,但我们确实找到了一种方法可以实现,而我正试图这样做。 Techpriester 指出我可以将字符串'$ foo-&gt; bar'传递给一个函数并让它解析它eval()。不是我想采取的方法,但值得一提。
  • Peter Bailey 指出在传递给函数之前会对$foo->bar之类的内容进行评估。我应该想到这一点,但由于某种原因没有。谢谢,彼得!
  • Will Vousden 表明通过引用传递$foo->$bar允许函数对其进行评估,而不是事先对其进行评估。他的函数显示isset($foo->bar)如果$foo不是一个我不知道的对象,就不会抱怨。

更有趣的是,他的例子似乎暗示 PHP等待评估变量,直到绝对必须。

如果你传递按值,那么PHP当然必须确定。像这样:

$foo->bar = 'hi';
somefunction($foo->bar); // same as somefunction('hi');

但是,如果您通过引用传递 ,它可以等待实际需要时确定该值。

像这样(遵循事情发生的顺序):

echo ifSet($foo->bar); // PHP has not yet evaluated $foo->bar...
function ifSet(&$somevar){ // ...because we're passing by reference (&$somevar)
  // Now we're inside the function, but it still hasn't evaluated $foo->bar; it 
  // just made its local variable, $somevar, point to the same thing as $foo->bar
  if(isset($somevar)){ // Right HERE is where it's evaluated - when we need it
    return $bar;
  }
}

感谢所有回复的人!如果我有错误的话,请告诉我。

7 个答案:

答案 0 :(得分:6)

您可以通过引用传递它:

<?php

function foo(&$bar)
{
    if (isset($bar))
    {
        echo "$bar\r\n";
    }
    else
    {
        echo "It's not set!\r\n";
    }
}

$baz = new stdClass;
$baz->test = 'test';
foo($baz->test);
foo($baz->test2);

$baz = array();
foo($baz['test3']);

?>

请注意,如果您尝试将对象作为数组访问,则无法使用此功能,反之亦然。

不过,你不应该过分依赖这样的事情。

答案 1 :(得分:3)

也许在这个非常具体的情况下你可以使用@符号:

<input value="<?php echo @$foo->bar; ?> "/>

答案 2 :(得分:2)

你永远无法做到这样的事情

echoIfSet($foo->bar);

是因为$foo->bar在发送到函数之前被评估了。如果该值是一个字符串,则所有echoIfSet()都将看到一个字符串 - 它不知道该字符串来自对象的属性。

所以,没有,总之。 PHP无法“剖析自己的语法”

您拥有的每个选项(使用__get()/ __ set()或Reflection)都会涉及到比您要避免的更多的代码和工作 - 而且它们仍然无法满足您的需求。

答案 3 :(得分:2)

将数组和对象包装在特殊数组中。你可以使用php魔术方法访问属性。

class wrap implements ArrayAccess{
  private $fields=array();
  function __get($name){
    if(isset($this->fields[$name])){
      return $this->fields[$name];
    }
  }
  function __set($name, $value){
    $this->fields[$name] = $value;
  }
  // with function isset()
  public function offsetExists($offset) {
    return isset($this->$fields[$offset]);
  }

  public function offsetGet($offset) {
    return $this->$fields[$offset];
  }

  public function offsetSet($offset, $value) {
    return $this->$fields[$offset] = $value;
  }

  public function offsetUnset($offset) {
    unset($this->$fields[$offset]);
  }
}

这将允许你做你想做的所有事情。

答案 4 :(得分:1)

有一种语言功能可以执行任何PHP代码,并将其作为字符串传递给它:eval()

但你真的,真的(如“我已经死了很严重”),不应该使用它。它导致的问题比它解决的问题多得多,并使你的代码无法维护。

通常有一种更好,更清洁的方式。

“eval()”导致了力量的黑暗面,我的意思是PHP。

如果你只想要提供字符串的“obj”和“attribute”部分,正则表达式可以做到这一点。它会像"/\$(\w+)->(\w+)/"。您可以将其提供给preg_match(),它会为您提供字符串组件。

答案 5 :(得分:0)

您是否只是在寻找eval声明?

答案 6 :(得分:0)

如果您正在寻找能够为您传递变量名称的内容,例如:

function foo($variable)
{
    echo variableName($variable);
}

$test = "Hello World";
// echoes "test"
foo($test);

然后你不会找到它。 PHP没有这样的功能。