Can PHP dissect its own syntax?
Can PHP dissect its own syntax? For example, I'd like to write a function that takes in an input like $object->attribute
and says to itself:
OK, he's giving me
$foo->bar
, which means he must think that$foo
is an object that has a property calledbar
. Before I try accessingbar
and potentially get a 'Trying to get property of non-object' error, l开发者_运维百科et me check whether$foo
is even an object.
The end goal is to echo a value if it is set, and fail silently if not.
I want to avoid repetition like this:
<input value="<? if(is_object($foo) && is_set($foo->bar)){ echo $foo->bar; }?> "/>
...and to avoid writing a function that does the above, but has to have the object and attribute passed in separately, like this:
<input value="<? echoAttribute($foo,'bar') ?>" />
...but to instead write something which:
- preserves the object->attribute syntax
- is flexible: can also handle array keys or regular variables
Like this:
<input value="<? echoIfSet($foo->bar); ?> />
<input value="<? echoIfSet($baz['buzz']); ?> />
<input value="<? echoIfSet($moo); ?> />
But this all depends on PHP being able to tell me "what kind of thing am I asking for when I say $object->attribute
or $array[$key]
", so that my function can handle each according to its own type.
Is this possible?
Update
I got some good answers here and did some experimenting. Wanted to summarize.
- The answer to my original question appears to be "no," but we did find a way to accomplish was I was trying to do. Techpriester pointed out that I could pass the string '$foo->bar' to a function and have it parse that and
eval()
it. Not the approach I want to take, but deserves a mention. - Peter Bailey pointed out that something like
$foo->bar
gets evaluated before getting passed to a function. I should have thought of this, but for some reason didn't. Thanks, Peter! - Will Vousden showed that passing
$foo->$bar
by reference allows the function to evaluate it, rather than having it evaluated beforehand. His function shows thatisset($foo->bar)
will not complain if$foo
is not an object, which I didn't know.
More interestingly, his example seems to imply that PHP waits to evaluate a variable until it absolutely has to.
If you're passing something by value, then of course PHP has to determine the value right then. Like this:
$foo->bar = 'hi';
somefunction($foo->bar); // same as somefunction('hi');
But if you're passing by reference, it can wait to determine the value when it actually needs to.
Like this (following the order in which things happen):
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;
}
}
Thanks to everyone who responded! If I've misstated something, please let me know.
You can pass it by reference:
<?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']);
?>
Note that this won't work if you try to access an object as an array or vice versa.
You shouldn't try to rely on something like this too much, though.
maybe in this very specific case you could use the @ symbol:
<input value="<?php echo @$foo->bar; ?> "/>
The reason you'll never be able to do something like this
echoIfSet($foo->bar);
Is because $foo->bar
is evaluated before its sent to the function. If that value is a string, all echoIfSet()
will see is a string - it has no idea that the string came from the property of an object.
So, no, in a word. PHP can't "dissect its own syntax"
Every option you have (using __get()/__set() or Reflection) involves more code and work than what you're trying to avoid - and they still don't get you exactly what you want.
Wrapping your array's and objects in a special array. you can acces the properties using php's magic methods.
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]);
}
}
this wil allow you to do all things you wanted.
There is a language feature that will execute any PHP code that you pass it as a string : eval()
.
But you really, really (as in "I'm dead serious"), should not use it. It causes much more problems than it solves and makes your code unmaintainable.
There's usually a better and cleaner way.
"eval()" leads to the dark side of the force, err I mean, of PHP.
If you just want the "obj" and "attribute" part of the supplied string, regular expression could do that. It'll be something like "/\$(\w+)->(\w+)/"
. You can feed this to preg_match()
and it will give you the string components.
Are you just looking for the eval
statement?
If you are looking for something that gives you the name of the variable you passed in, as in:
function foo($variable)
{
echo variableName($variable);
}
$test = "Hello World";
// echoes "test"
foo($test);
Then you are not going to find it. PHP doesn't have such a feature.
精彩评论