PHP : object method+proprety call from var - php

I want to call an object method+property with the content stored in a var ...
for example :
// setup the object
$xpath = new DOMXpath();
// setup the 'method'+'property' to call
$var1 = "query('something')->item(O)->nodeValue";
$return = $xpath->$var1();
Obviously, I make a mistake ... assuming that direct call is working, i.e.:
$return2 = $xpath->query('something')->item(0)->value;
echo "Return2 : ".$return2; //print okeedokee ...
How to pass args to query()? And how to add extra args to it?

I think you have to call
$return=$xpath->$var1;
Note : call_user_func is the function you need
Example :
alpha.php
class Alpha
{
public function getAlpha($arr_input)
{
echo "<pre>";
print_r($arr_input);
}
}
index.php
include_once 'alpha.php';
$post = array('one','two','three');
$obj_alpha = new Alpha();
call_user_func( array( $obj_alpha , 'getAlpha' ), $post ) ;
//here I call `getAlpha` function from object of class alpha (`$obj_alpha`)
with argument `$post`
//will print $post array

You can do this using eval():
$return = eval('return $xpath->' . $var1 .';');
However, using eval() with user-input is pretty much always a bad idea. So be careful there.

Related

Is it possible to pass a function as another function parameter? [duplicate]

I need to pass a function as a parameter to another function and then call the passed function from within the function...This is probably easier for me to explain in code..I basically want to do something like this:
function ($functionToBeCalled)
{
call($functionToBeCalled,additional_params);
}
Is there a way to do that.. I am using PHP 4.3.9
Thanks!
I think you are looking for call_user_func.
An example from the PHP Manual:
<?php
function barber($type) {
echo "You wanted a $type haircut, no problem";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?>
function foo($function) {
$function(" World");
}
function bar($params) {
echo "Hello".$params;
}
$variable = 'bar';
foo($variable);
Additionally, you can do it this way. See variable functions.
In php this is very simple.
<?php
function here() {
print 'here';
}
function dynamo($name) {
$name();
}
//Will work
dynamo('here');
//Will fail
dynamo('not_here');
I know the original question asked about PHP 4.3, but now it's a few years later and I just wanted to advocate for my preferred way to do this in PHP 5.3 or higher.
PHP 5.3+ now includes support for anonymous functions (closures), so you can use some standard functional programming techniques, as in languages like JavaScript and Ruby (with a few caveats). Rewriting the call_user_func example above in "closure style" would look like this, which I find more elegant:
$barber = function($type) {
echo "You wanted a $type haircut, no problem\n";
};
$barber('mushroom');
$barber('shave');
Obviously, this doesn't buy you much in this example - the power and flexibility comes when you pass these anonymous functions to other functions (as in the original question). So you can do something like:
$barber_cost = function($quantity) {
return $quantity * 15;
};
$candy_shop_cost = function($quantity) {
return $quantity * 4.50; // It's Moonstruck chocolate, ok?
};
function get_cost($cost_fn, $quantity) {
return $cost_fn($quantity);
}
echo '3 haircuts cost $' . get_cost($barber_cost, 3) . "\n";
echo '6 candies cost $' . get_cost($candy_shop_cost, 6) . "\n";
This could be done with call_user_func, of course, but I find this syntax much clearer, especially once namespaces and member variables get involved.
One caveat: I'll be the first to admit I don't know exactly what's going on here, but you can't always call a closure contained in a member or static variable, and possibly in some other cases. But reassigning it to a local variable will allow it to be invoked. So, for example, this will give you an error:
$some_value = \SomeNamespace\SomeClass::$closure($arg1, $arg2);
But this simple workaround fixes the issue:
$the_closure = \SomeNamespace\SomeClass::$closure;
$some_value = $the_closure($arg1, $arg2);
You could also use call_user_func_array(). It allows you to pass an array of parameters as the second parameter so you don't have to know exactly how many variables you're passing.
If you need pass function with parameter as parameter, you can try this:
function foo ($param1){
return $param1;
}
function bar ($foo_function, $foo_param){
echo $foo_function($foo_param);
}
//call function bar
bar('foo', 'Hi there'); //this will print: 'Hi there'
phpfiddle example
Hope it'll be helpful...
If you want to do this inside a PHP Class, take a look at this code:
// Create a sample class
class Sample
{
// Our class displays 2 lists, one for images and one for paragraphs
function __construct( $args ) {
$images = $args['images'];
$items = $args['items'];
?>
<div>
<?php
// Display a list of images
$this->loop( $images, 'image' );
// notice how we pass the name of the function as a string
// Display a list of paragraphs
$this->loop( $items, 'content' );
// notice how we pass the name of the function as a string
?>
</div>
<?php
}
// Reuse the loop
function loop( $items, $type ) {
// if there are items
if ( $items ) {
// iterate through each one
foreach ( $items as $item ) {
// pass the current item to the function
$this->$type( $item );
// becomes $this->image
// becomes $this->content
}
}
}
// Display a single image
function image( $item ) {
?>
<img src="<?php echo $item['url']; ?>">
<?php
}
// Display a single paragraph
function content( $item ) {
?>
<p><?php echo $item; ?></p>
<?php
}
}
// Create 2 sample arrays
$images = array( 'image-1.jpg', 'image-2.jpg', 'image-3.jpg' );
$items = array( 'sample one', 'sample two', 'sample three' );
// Create a sample object to pass my arrays to Sample
$elements = { 'images' => $images, 'items' => $items }
// Create an Instance of Sample and pass the $elements as arguments
new Sample( $elements );

&$variable in PHP

I have been looking through wordpress's core files and stumbled across this piece of code, I noticed it had an ampersand before a variable name and after an =.
I have tried searching this and came across this from the PHP manual and it doesn't explain it well, or I'm looking at the wrong one! I also saw that it is used to modify a variable outside of the method where it is being used, but, thats what a variable is there for, to be modified so if this is correct how would one use it?
function _make_cat_compat( &$category ) {
if ( is_object( $category ) ) {
$category->cat_ID = &$category->term_id;
$category->category_count = &$category->count;
$category->category_description = &$category->description;
$category->cat_name = &$category->name;
$category->category_nicename = &$category->slug;
$category->category_parent = &$category->parent;
} elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
$category['cat_ID'] = &$category['term_id'];
$category['category_count'] = &$category['count'];
$category['category_description'] = &$category['description'];
$category['cat_name'] = &$category['name'];
$category['category_nicename'] = &$category['slug'];
$category['category_parent'] = &$category['parent'];
}
}
This means the function will modify the argument (by reference) instead working on a copy of it. Remove all the ampersands inside the body of the function, only the one in the argument is necessary.
function foo(&$foo) { $foo++; }
function bar($foo) { $foo++; }
$foo = 10;
foo($foo);
foo($foo);
// prints 12, function foo() has incremented var $foo twice
echo "$foo\n";
bar($foo);
// still 12, as bar() is working on a copy of $foo
echo "$foo\n";
// However, since PHP 5.0, all objects are passed by reference [(or to be more specific, by identifier)][1]
class Foo {
public $bar = 10;
}
$obj = new Foo;
echo "$obj->bar\n"; // 10, as expected
function objectIncrement($obj) { $obj->bar++; }
function objectRefIncrement(&$obj) { $obj->bar++; }
objectIncrement($obj);
echo "$obj->bar\n"; // 11, as expected, since objects are ALWAYS passed by reference (actually by identifier)
objectRefIncrement($obj);
echo "$obj->bar\n"; // 12
It's still a good idea, if you intend to modify the passed argument in a function/method, to explicitly pass it by reference. Aside from other advantages, your code also becomes more explicit and understandable.
BTW, you can do this:
function _make_cat_compat( &$category ) {
if (is_array( $category)) {
$category = (object)$category;
}
$category->cat_ID = $category->term_id;
$category->category_count = $category->count;
$category->category_description = $category->description;
$category->cat_name = $category->name;
$category->category_nicename = $category->slug;
$category->category_parent = $category->parent;
}
Looks cleaner to me, but I don't know your specific case. And I don't know how you would have either array or object - it implies some bad practices used.
When talking about method parameters, &$variable refers to a call by reference. So any change you make to this variable remains even if the method is done.
function a($arg) // call by value ($arg is a copy of the original)
{
$arg += 1;
}
function b(&$arg) // call by reference ($arg IS the original)
{
$arg += 1;
}
$myArg = 1;
a($myArg);
echo $myArg;
echo "\r\n";
b($myArg);
echo $myArg;
// Displays:
// 1
// 2
Here is the section of the PHP manual about references.
The & after the = basically means the same, but they are useless in this context because you already have a call by reference anyway. You can safely remove them.
Here's the correct PHP manual entry on references: http://php.net/manual/en/language.references.php
In most cases you don't need to pass a reference using the ampersand & as PHP will always pass a reference first and only create a copy of the variable on the first write access.
It is passing the variable as a reference. Without the ampersand the following code wouldnt work:
$var = "content";
function test(&$v)
{
$v = "this is new content";
}
test($var);
NOTE: this is untested code, but the theory is close enough. It allows to modify the variable from within a different scope, so rather than passing the value of a variable, in this example - "content", you are passing a reference to the variable itself, so you are directly editing the variable you passed in.
Its because this function doesnt return anything, just modify, and all.

Directly display the value of an array returned by a method

Is it possible to do in one line calling a method that returns an array() and directly get a value of this array ?
For example, instead of :
$response = $var->getResponse()->getResponseInfo();
$http_code = $response['http_code'];
echo $http_code;
Do something like this :
echo $var->getResponse()->getResponseInfo()['http_code'];
This example does not work, I get a syntax error.
If you're using >= PHP 5.4, you can.
Otherwise, you'll need to use a new variable.
What you can do is to pass the directly to your function. Your function should be such that if a variable name is passed to it, it should the value of that variable, else an array with all variables values.
You can do it as:
<?php
// pass your variable to the function getResponseInfo, for which you want the value.
echo $var->getResponse()->getResponseInfo('http_code');
?>
Your function:
<?php
// by default, it returns an array of all variables. If a variable name is passed, it returns just that value.
function getResponseInfo( $var=null ) {
// create your array as usual. let's assume it's $result
/*
$result = array( 'http_code'=>200,'http_status'=>'ok','content_length'=>1589 );
*/
if( isset( $var ) && array_key_exists( $var, $result ) ) {
return $result[ $var ];
} else {
return $result;
}
}
?>
Hope it helps.
Language itself does not support that for an array.
In case you can change what getResponseInfo() return:
You can create simple class, which will have array as an constructor parameter. Then define magical getter which will be just pulling the keys from the instance array
function __get($key)
{
return #content[$key]
}
Then you'll be able to do
echo $var->getResponse()->getResponseInfo()->http_code;
// or
echo $var->getResponse()->getResponseInfo()->$keyWhichIWant;
What i wrote is just proposal. The real __get method should have some check if the exists and so

Dynamically call Class with variable number of parameters in the constructor

I know that it is possible to call a function with a variable number of parameters with call_user_func_array() found here -> http://php.net/manual/en/function.call-user-func-array.php . What I want to do is nearly identical, but instead of a function, I want to call a PHP class with a variable number of parameters in it's constructor.
It would work something like the below, but I won't know the number of parameters, so I won't know how to instantiate the class.
<?php
//The class name will be pulled dynamically from another source
$myClass = '\Some\Dynamically\Generated\Class';
//The parameters will also be pulled from another source, for simplicity I
//have used two parameters. There could be 0, 1, 2, N, ... parameters
$myParameters = array ('dynamicparam1', 'dynamicparam2');
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters
//not just two parameters.
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]);
You can do the following using ReflectionClass
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = array ('dynamicparam1', 'dynamicparam2');
$reflection = new \ReflectionClass($myClass);
$myClassInstance = $reflection->newInstanceArgs($myParameters);
PHP manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php
Edit:
In php 5.6 you can achieve this with Argument unpacking.
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = ['dynamicparam1', 'dynamicparam2'];
$myClassInstance = new $myClass(...$myParameters);
I implement this approach a lot when function args are > 2, rather then end up with an Christmas list of arguments which must be in a specific order, I simply pass in an associative array. By passing in an associative array, I can check for necessary and optional args and handle missing values as needed. Something like:
class MyClass
{
protected $requiredArg1;
protected $optionalArg1;
public function __construct(array $options = array())
{
// Check for a necessary arg
if (!isset($options['requiredArg1'])) {
throw new Exception('Missing requiredArg1');
}
// Now I can just localize
$requiredArg1 = $options['requiredArg1'];
$optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null;
// Now that you have localized args, do what you want
$this->requiredArg1 = $requiredArg1;
$this->optionalArg1 = $optionalArg1;
}
}
// Example call
$class = 'MyClass';
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!');
$instance = new $class($array);
var_dump($instance->getRequiredArg1());
var_dump($instance->getOptionalArg1());
I highly recommend using an associative array, however it is possible to use a 0-index array. You will have to be extremely careful when constructing the array and account for indices that have meaning, otherwise you will pass in an array with offset args and wreck havoc with your function.
You can do that using func_get_args().
class my_class {
function __construct( $first = NULL ) {
$params = func_get_args();
if( is_array( $first ) )
$params = $first;
// the $params array will contain the
// arguments passed to the child function
foreach( $params as $p )
echo "Param: $p\n";
}
}
function my_function() {
$instance = new my_class( func_get_args() );
}
echo "you can still create my_class instances like normal:";
$instance = new my_class( "one", "two", "three" );
echo "\n\n\n";
echo "but also through my_function:";
my_function( "one", "two", "three" );
Basically, you simply pass the result of func_get_args to the constructor of your class, and let it decide whether it is being called with an array of arguments from that function, or whether it is being called normally.
This code outputs
you can still create my_class instances like normal:
Param: one
Param: two
Param: three
but also through my_function:
Param: one
Param: two
Param: three
Hope that helps.
I've found here
Is there a call_user_func() equivalent to create a new class instance?
the example:
function createInstance($className, array $arguments = array())
{
if(class_exists($className)) {
return call_user_func_array(array(
new ReflectionClass($className), 'newInstance'),
$arguments);
}
return false;
}
But can somebody tell me if there is an example for classes with protected constructors?

Forward undefined number of arguments to another function

I will explain the question with a simple function accepting any number of function
function abc() {
$args = func_get_args();
//Now lets use the first parameter in something...... In this case a simple echo
echo $args[0];
//Lets remove this first parameter
unset($args[0]);
//Now I want to send the remaining arguments to different function, in the same way as it received
.. . ...... BUT NO IDEA HOW TO . ..................
//tried doing something like this, for a work around
$newargs = implode(",", $args);
//Call Another Function
anotherFUnction($newargs); //This function is however a constructor function of a class
// ^ This is regarded as one arguments, not mutliple arguments....
}
I hope the question is clear now, what is the work around for this situation?
Update
I forgot to mention that the next function I am calling is a constructor class of another class.
Something like
$newclass = new class($newarguments);
for simple function calls
use call_user_func_array, but do not implode the args, just pass the array of remaining args to call_user_func_array
call_user_func_array('anotherFunction', $args);
for object creation
use: ReflectionClass::newInstanceArgs
$refClass = new ReflectionClass('yourClassName');
$obj = $refClass->newInstanceArgs($yourConstructorArgs);
or: ReflectionClass::newinstance
$refClass = new ReflectionClass('yourClassName');
$obj = call_user_func_array(array($refClass, 'newInstance'), $yourConstructorArgs);

Categories