I have created two code snippets at
http://codepad.viper-7.com/o5MxgF
and http://codepad.viper-7.com/qUpTag
In the second snippet, I was trying to use array as a call back because I found at
http://www.php.net/manual/en/language.types.array.php
that
Note: Both square brackets and curly braces can be used
interchangeably for accessing array elements (e.g. $array[42] and
$array{42} will both do the same thing in the example above).
So, I thought I could use array as a function so that I don't need the declare
$get_new_key = function ($k) use($fa) {
return $fa[$k];
};
But as you can see, I was getting a
: array_map() expects parameter 1 to be a valid callback, first array
member is not a valid class name or object in /code/qUpTag on line 8
error.
Are there anything to make array a callable without creating a companion function to access its values?
Thanks.
Having a callable array doesn't mean that it returns the values of the array. Instead, it's an array that points to a method on either a class or object.
For instance, array('MyClass', 'my_method') is a callable for the static method my_method on MyClass and array($object, 'method') is a callable for the instance method method on the object in $object.
You can read more about the callable type in the PHP documentation
Related
Let's assume we have this function
<?php
function run($callback)
{
$callback($some, $params);
}
How to call it?
run($someObject->callback);
or rather
run([$someObject, 'callback']);
The first one seems better to me especially because of code suggestion but in documentation is used array notation.
Why is first one worse than second one?
The array notation is better because the arrow notation doesn't work. Functions in PHP aren't first class objects which can be passed around. Whenever you "pass a function", you must pass it by name; i.e. only its name. To pass an object method, you need to pass the object and the method name using the callable pseudo type notation.
This article has the following method:
/**
* Call protected/private method of a class.
*
* #param object &$object Instantiated object that we will run method on.
* #param string $methodName Method name to call
* #param array $parameters Array of parameters to pass into method.
*
* #return mixed Method return.
*/
public function invokeMethod(&$object, $methodName, array $parameters = array())
{
$reflection = new \ReflectionClass(get_class($object));
$method = $reflection->getMethod($methodName);
$method->setAccessible(true);
return $method->invokeArgs($object, $parameters);
}
My question is... is there a particular reason why $object has an ampersand before it in the function declaration? Normally that'd mean you were passing by reference but doens't PHP pass objects by reference by default?
My question is... is there a particular reason why $object has an
ampersand before it in the function declaration?
In this piece of code, no. $object is only used for its value inside this function. The only two places where it is used are to be passed to get_class() (which takes its argument by value), and to be passed to ReflectionMethod::invokeArgs() (which also takes its arguments by value).
Therefore, there was no point to take $object by reference.
As you can see in the Function arguments section of the PHP documentation:
PHP supports passing arguments by value (the default), passing by reference, and default argument values. Variable-length argument lists are also supported.
By default, arguments are passed by value.
As for objects, it may seem that they are passed by reference but that is not totally true. See Objects and references which states:
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
So, to avoid confusion, I would always assume that the parameter is NOT passed by value, even for an object. If you want it to be passed by reference, add the & to make sure you are really passing it by reference.
Here is an example with an object:
<?php
// Passed by value... won't be affected
function byValue($arg) {
$arg = null;
}
// Passed by reference... will be affected
function byReference(&$arg) {
$arg = null;
}
$obj = new StdClass;
var_dump($obj); // Untouched object created
byValue($obj);
var_dump($obj); // After 'trying' to set it to null
byReference($obj);
var_dump($obj); // After setting it to null for real
Run demo
Say we have the object $teams (an associative array) containing an object that provides the method getMembers() which returns an Array as follows:
$membersArray = $teams['blueteam']->getMembers();
If I want to then access individual members, I may do so as follows:
$membersArray[1];
Why can't I perform the access in-line as follows, and is there a proper way to do so in PHP?
$membersArray = $teams['blueteam']->getMembers()[1];
Support for this added in PHP 5.4.0:
$membersArray = $teams['blueteam']->getMembers()[1];
Rather than try to access it like that, why not make an alternative method called getMember() which accepts a parameter for the array index. For example:
function getMember( $index )
{
return $this->members[$index];
}
This makes your code a little more self-documenting by indicating getMembers will return an array of members, where getMember() will only return a single array element.
hi I working with Drupal and it uses arrays to a level I'm not very familier with, I've a quick question which is what is the difference between these 'selectors'(is that the right term)?
This causes an error "Fatal error: Cannot use object of type stdClass as array in..."
$node['field_geoloc']
this works (im using it in an if != null statement)
$node->field_geoloc
hopefully an easy question...
thanks.
Pretty easy.. the error says it all:
"Fatal error: Cannot use object of type stdClass as array in..."
You are attempting to use an object as an array.
Object properties aren't accessibly using the $array['key'] method that you are used to. You need to access properties like:
`$object->property`
If you have an object, you can get the properties from that array by using the get_object_vars method. But I know from experience that you should not use that method with a $node in Drupal.
-> is operator for accessing public object properties (and call public methods). In order for an object properties to be accessed with $object['key'] syntax, it have to implement ArrayAccess. Other option is to cast the object to array ( $node = (array) $node (but this will work only for first-level keys, e.g. it will turn $node->page to $node['page'], but not $node->page->title to $node['page']['title'] - the later will be accessible via $node['page']->title
Because you can't use object as an array.
That first is an array and that second is an object.
The first one is an array, the second one is an object (of class StdClass).
But you may be interested in this interface: http://php.net/manual/en/class.arrayaccess.php which allows accessing an object as an array (so you do $obj['key'] instead of $obj->key)
This question already has answers here:
unpacking an array of arguments in php
(5 answers)
Closed 6 months ago.
In Python, you can pack and unpack arguments like so:
def myfunction(arg1, arg2, arg3):
pass
mydict = dict(arg1='foo', arg2='bar', arg3='baz')
myfunction(**mydict)
mylist = ['foo', 'bar', 'baz']
myfunction(*mylist)
Now, is there something similar in PHP? I have a class that is passed to a function, along with an associative array extracted from a database record. I want to create an instance of the class, which accepts arguments that are named the same as the keys in the array. Can it be done?
EDIT
Ok, so I definitely didn't formulate my question correctly. I wanted to instantiate a new class dynamically when I know neither the class name, nor the number of arguments beforehand.
I've found the Answer though:
http://php.net/manual/en/book.reflection.php
Here's the solution:
class MyClass {
public function __construct($var1, $var2, $var3) {
echo "$var1\n";
echo "$var2\n";
echo "$var3\n";
}
}
$reflector = new ReflectionClass('MyClass');
$args = array('var1'=>'foo', 'var2'=>'baz', 'var3'=>'bar');
$instance = $reflector->newInstanceArgs($args);
No you can't do it directly, you'll have to manually extract the values from the array and pass them to the constructor, or change it so that it accepts an array as argument.
You might take a look at call_user_func_array but I don't think you can use it with a constructor as you need an instance of the object to call one of its methods.
Note that the param list unpacking myfunc(*args) can be achieved with call_user_func_array():
$args = array("foo", "bar", "baz");
call_user_func_array("myfunc", $args);
For object methods you can use call_user_func_array(array($obj, "__construct"), $args). The deficiency here is the __constructor thus would be invoked twice, so should not do any funny things. Otherwise a specific init method is necessary.
Due to lack of named parameters an equivalent to myfunc(**args) does not exist in PHP. A common idiom is therefore to just pass the dict/array in, and let the function handle named params.