I know how PHP dynamic vars work, I know I can access object property like
$object->{'somethingWith$var'}; or like $object->$var;
But what I try to accomplish is to access $object->property->subproperty from $object and the string $string = 'property->subproperty';.
I tryed $object->$string, $object->{$string}, $object->$$string hahaha, none worked.
Does anybody know how to do this ? :)
You can write simple function, something like this:
function accessSubproperty($object, $accessString) {
$parts = explode('->', $accessString);
$tmp = $object;
while(count($parts)) {
$tmp = $tmp->{array_shift($parts)};
}
return $tmp;
}
There is no way to do this like that.
You have to first assign $property = $object->$propertyName and then access var you wanted to $property->$subpropertyName.
In your examples string property->subproperty will be treated like variable name which obviously doesn't exist.
It is not working because all you are accomplishing with your tries is getting $object{'property->subproperty'} which off course is not the same as $object->{'property'}->{'subproperty'}.
What you can do is:
$ret = $object;
foreach (explode("->",$string) as $bit)
$ret = $ret->$bit;
Or you will have to go to the ugly and evil eval() (let the downvoting start):
eval("return \$object->$string;")
Related
I want to know how can I concatenate [und][0][value].
I don't want to write every time [und][0][value]. So I have do like this:
<?php
$und_value = $load->field_testimonial_location['und'][0]['value'];
$query = db_select('node','n');
$query->fields('n',array('nid'));
$query->condition('n.type','testimonial','=');
$result = $testimonial_query->execute();
while($fetch = $result->fetchObject()){
$load = node_load($fetch->nid);
// $location = $load->field_testimonial_location['und'][0]['value'];
$location = $load->field_testimonial_location.$und_value;
echo $location;
}
But its not working. It outputs Array Array So have any idia for this problem? How can I do? Full code here
Why don't you make some function which will take node field as parameter and return it's value
function field_value($field){
return $field['und'][0]['value'];
}
Something like that (not tested).
But if you don't want to use function try using curly braces like:
$location = $load->{field_testimonial_location.$und_value};
That should work...
Extending answer posted by MilanG, to make function more generic
function field_value($field, $index = 0 ){
return $field['und'][$index]['value'];
}
There are time when you have multi value fields, in that case you have to pass index of the value also. For example
$field['und'][3]['value'];
Please do not use such abbreviations, they will not suit all cases and eventually break your code.
Instead, there is already a tool do create custom code with easier syntax: Entity Metadata Wrapper.
Basically, instead of
$node = node_load($nid);
$field_value = $node->field_name['und'][0]['value'];
you can then do something like
$node = node_load($nid);
$node_wrapper = entity_metadata_wrapper('node', $node);
$field_value = $node_wrapper->field_name->value();
With the node wrapper you can also set values of a node, it's way easier and even works in multilingual environments, no need to get the language first ($node->language) or use constants (LANGUAGE_NONE).
In my custom module, I often use $node for the node object and $enode for the wrapper object. It's equally short and still know which object I am working on.
This a little hard for me to explain, but I'll try my best. I'm trying to find the best way to create an instance of a closure. Below is an example of how I am creating and accessing the closure:
$myvar->parse('var1, var2', function () {
//my code
});
I then loop through the strings by exploding the comma and put it into an array like so.
$array = array();
$array['var1'] = closure();
$array['var2'] = closure();
Later on in my code I use call_user_func to execute the function.
Now, the issue I'm having is that when I access $array['var1'] it calls the closure without any problem.
But when I access $array['var2'] it does nothing. I've been looking at diverse websites for a while without much luck. Do I need to use pointers (tried without success) or create a new instance of it somehow?
I currently only have access to php 5.3 on my server, so I can't use any of the awesome stuff in 5.4 :(
I'd really appreciate any feedback and advice you may have.
$yourcall = function () {
//code
};
$array['var1'] = $yourcall;
$array['var2'] = $yourcall;
Would assign the closure to those values. However:
$array['var1'] = $yourcall();
$array['var2'] = $yourcall();
As you seem to have would assign the result of calling that closure to the array items.
In your parse function (why does it take a string and not an array), I assume you want this:
function parse($string,$closure){
$array = array();
foreach(explode(',',$string) as $key) $array[$key] = $closure;
return $array;
}
Yes your question isn't clear. You knew it so I wonder why you didn't explained better.
Anyway if you need to run a closure stored inside $array['var2'] you have to specifically put in your code something like this:
$array['var2'] = function(){
//> Code
};
That's the only way
By guessing at your code, your function parse should like:
function parse($keys,$func) {
$array = array();
foreach(explode(',',$keys) as $v) {
$array[trim($v)] = $func; //> trim important here!
}
}
Most likely you have forgot to trim($v)
func($name1) should return name1
Is it possible?
Here's a function that does it.
function var_name (&$iVar, &$aDefinedVars)
{
foreach ($aDefinedVars as $k=>$v)
$aDefinedVars_0[$k] = $v;
$iVarSave = $iVar;
$iVar =!$iVar;
$aDiffKeys = array_keys (array_diff_assoc ($aDefinedVars_0, $aDefinedVars));
$iVar = $iVarSave;
return $aDiffKeys[0];
}
Call it like this
$test = "blah";
echo var_name($test, get_defined_vars());
That will print out "test".
I originally found that function over here You can also do it by iterating over the array returned by get_defined_vars(). That might be a bit easier to understand.
No, there is no way to get the name of a variable in PHP.
When calling a function, that function will only receive the content of the variable, and not the "variable itself" -- which means a function cannot find out the name of the variable that was passed to it.
Good Idea ? No
Any usecase you where you should do it ? No
Proof of concept ? Sure !
<?php
a($test);
function a($x) {
$trace = debug_backtrace();
$file = file($trace[0]['file']);
$line = $file[$trace[0]['line']-1];
var_dump($line); // Prints "a($test);" Do the Stringparsing and your done
}
Yes, this takes the "easy" by reading the sourcefile, it is also doable by using a php extension called "bytekit" that gives you userland access to the php opcodes and work from there.
No.
When you define a function, you specify a local variable name for it to have inside the scope of that function. PHP will pass the function the appropriate value, but the symbol is no longer in scope.
You could look into using "variable variables" as an alternative, however.
Obviously, it is possible for sufficiently high values of crazy.
The comments on this page include several techniques:
http://php.net/manual/en/language.variables.php
lucas dot karisny at linuxmail dot org's answer works on my machine:
http://www.php.net/manual/en/language.variables.php#49997
YMMV.
I want to trigger a function based on a variable.
function sound_dog() { return 'woof'; }
function sound_cow() { return 'moo'; }
$animal = 'cow';
print sound_{$animal}(); *
The * line is the line that's not correct.
I've done this before, but I can't find it. I'm aware of the potential security problems, etc.
Anyone? Many thanks.
You can do that, but not without interpolating the string first:
$animfunc = 'sound_' . $animal;
print $animfunc();
Or, skip the temporary variable with call_user_func():
call_user_func('sound_' . $animal);
You can do it like this:
$animal = 'cow';
$sounder = "sound_$animal";
print ${sounder}();
However, a much better way would be to use an array:
$sounds = array('dog' => sound_dog, 'cow' => sound_cow);
$animal = 'cow';
print $sounds[$animal]();
One of the advantages of the array method is that when you come back to your code six months later and wonder "gee, where is this sound_cow function used?" you can answer that question with a simple text search instead of having to follow all the logic that creates variable function names on the fly.
http://php.net/manual/en/functions.variable-functions.php
To do your example, you'd do
$animal_function = "sound_$animal";
$animal_function();
You can use curly brackets to build your function name. Not sure of backwards compatibility, but at least PHP 7+ can do it.
Here is my code when using Carbon to add or subtract time based on user chosen type (of 'add' or 'sub'):
$type = $this->date->calculation_type; // 'add' or 'sub'
$result = $this->contactFields[$this->date->{'base_date_field'}]
->{$type.'Years'}( $this->date->{'calculation_years'} )
->{$type.'Months'}( $this->date->{'calculation_months'} )
->{$type.'Weeks'}( $this->date->{'calculation_weeks'} )
->{$type.'Days'}( $this->date->{'calculation_days'} );
The important part here is the {$type.'someString'} sections. This will generate the function name before executing it. So in the first case if the user has chosen 'add', {$type.'Years'} becomes addYears.
For PHP >= 7 you can use this way:
function sound_dog() { return 'woof'; }
function sound_cow() { return 'moo'; }
$animal = 'cow';
print ("sound_$animal")();
You should ask yourself why you need to be doing this, perhaps you need to refactor your code to something like the following:
function animal_sound($type){
$animals=array();
$animals['dog'] = "woof";
$animals['cow'] = "moo";
return $animals[$type];
}
$animal = "cow";
print animal_sound($animal);
You can use $this-> and self:: for class-functions. Example provided below with a function input-parameter.
$var = 'some_class_function';
call_user_func(array($this, $var), $inputValue);
// equivalent to: $this->some_class_function($inputValue);
And yet another solution to what I like to call the dog-cow problem. This will spare a lot of superfluous function names and definitions and is perfect PHP syntax and probably future proof:
$animal = 'cow';
$sounds = [
'dog' => function() { return 'woof'; },
'cow' => function() { return 'moo'; }
];
print ($sounds[$animal])();
and looks a little bit less like trickery as the "string to function names" versions.
JavaScript devs might prefer this one for obvious reasons.
(tested on Windows, PHP 7.4.0 Apache 2.4)
any idea how if the following is possible in PHP as a single line ?:
<?php
$firstElement = functionThatReturnsAnArray()[0];
... It doesn't seem to 'take'. I need to do this as a 2-stepper:
<?php
$allElements = functionThatReturnsAnArray();
$firstElement = $allElements[0];
... just curious - other languages I play with allow things like this, and I'm lazy enoug to miss this in PHP ... any insight appreciated ...
#Scott Reynen
that's not true. This will work:
list(,,$thirdElement) = $myArray;
Try:
<?php
$firstElement = reset(functionThatReturnsAnArray());
If you're just looking for the first element of the array.
Unfortunately, that is not possible with PHP. You have to use two lines to do it.
You can do this in one line! Use array_shift().
<?php
echo array_shift(i_return_an_array());
function i_return_an_array() {
return array('foo', 'bar', 'baz');
}
When this is executed, it will echo "foo".
list() is useful here. With any but the first array element, you'll need to pad it with useless variables. For example:
list( $firstElement ) = functionThatReturnsAnArray();
list( $firstElement , $secondElement ) = functionThatReturnsAnArray();
And so on.
I actually use a convenience function i wrote for such purposes:
/**
* Grabs an element from an array using a key much like array_pop
*/
function array_key_value($array, $key) {
if(!empty($array) && array_key_exists($key, $array)) {
return $array[$key];
}
else {
return FALSE;
}
}
then you just call it like so:
$result = array_key_value(getMeAnArray(), 'arrayKey');
You can use array_slice(), like so:
$elementX = array_slice(functionThatReturnsAnArray(), $x, 1);
Also noticed that end() is not mentioned. It returns the last element of an array.
Either current($array) or array_shift($array) will work, the former will leave the array intact.
nickf, good to know, thanks. Unfortunately that has readability problems beyond a few commas.
I think any of the above would require a comment to explain what you're doing, thus becoming two lines. I find it simpler to do:
$element = functionThatReturnsArray();
$element = $element[0];
This way, you're not using an extra variable and it's obvious what you're doing.
$firstItem = current(returnsArray());
Well, I have found a couple of ways to get what you want without calling another function.
$firstElement = ($t = functionThatReturnsAnArray()) ? $t[0] : false;
and for strings you could use
$string = (($t = functionThatReturnsAnArray())==0) . $t[0];
.. Interesting problem
Draco
I am guessing that this is a built-in or library function, since it sounds like you cannot edit it directly. I recommend creating a wrapper function to give you the output you need:
function functionThatReturnsOneElement( $arg )
{
$result = functionThatReturnsAnArray( $arg );
return $result[0];
}
$firstElement = functionThatReturnsOneElement();
As far as I know this is not possible, I have wanted to do this myself several times.
http://us3.php.net/reset
Only available in php version 5.
If it's always the first element, you should probably think about having the function return just the first item in the array. If that is the most common case, you could use a little bit of coolness:
function func($first = false) {
...
if $first return $array[0];
else return $array;
}
$array = func();
$item = func(true);
My php is slightly rusty, but i'm pretty sure that works.
You can also look at array_shift() and array_pop().
This is probably also possible:
array(func())[0][i];
The 0 is for the function.
Sometimes I'll change the function, so it can optionally return an element instead of the entire array:
<?php
function functionThatReturnsAnArray($n = NULL) {
return ($n === NULL ? $myArray : $myArray[$n]);
}
$firstElement = functionThatReturnsAnArray(0);