What kind of array does PHP use? - Stack Overflow
php - Type hinting - specify an array of objects - Stack Overflow
PHP arrays aren't really arrays
Benchmark Analysis of PHP Array Loops
Why don't you show the actual code of the 5 methods? It's really crucial. I'm especially intrigued by the foreach result, because you didn't mention reference in your 5 bullet-points list.
More on reddit.comPHP is not as strict as C or C++. In PHP you don't need to specify the type of data to be placed in an array, you don't need to specify the array size either.
If you need to declare an array of integers in C++ you can do it like this:
int array[6];
This array is now bound to only contain integers. In PHP an array can contain just about everything:
$arr = array();
$arr[] = 1;
$arr[] = 2;
$arr[] = 3;
$arr[] = 4;
var_dump($arr); //Prints [1,2,3,4]
$arr[] = 'hello world'; //Adding a string. Completely valid code
$arr[] = 3.14; //Adding a float. This one is valid too
$arr[] = array(
'id' => 128,
'firstName' => 'John'
'lastName' => 'Doe'
); //Adding an associative array, also valid code
var_dump($arr); //prints [1,2,3,4,'hello world',3.14, [ id => 128, firstName => 'John', lastName => 'Doe']]
If you're coming from a C++ background it's best to view the PHP array as a generic vector that can store everything.
From php.net
An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.
If you want to ensure you are working with "Array of Foo" and you want to ensure methods receive "Array of Foo", you can:
class ArrayOfFoo extends \ArrayObject {
public function offsetSet($key, $val) {
if ($val instanceof Foo) {
return parent::offsetSet($key, $val);
}
throw new \InvalidArgumentException('Value must be a Foo');
}
}
then:
function workWithFoo(ArrayOfFoo $foos) {
foreach ($foos as $foo) {
// etc.
}
}
$foos = new ArrayOfFoos();
$foos[] = new Foo();
workWithFoo($foos);
The secret sauce is that you're defining a new "type" of "array of foo", then passing that "type" around using type hinting protection.
The Haldayne library handles the boilerplate for membership requirement checks if you don't want to roll your own:
class ArrayOfFoo extends \Haldayne\Boost\MapOfObjects {
protected function allowed($value) { return $value instanceof Foo; }
}
(Full-disclosure, I'm the author of Haldayne.)
Historical note: the Array Of RFC proposed this feature back in 2014. The RFC was declined with 4 yay and 16 nay. The concept recently reappeared on the internals list, but the complaints have been much the same as levied against the original RFC: adding this check would significantly affect performance.
Old post but variadic functions and array unpacking can be used (with some limitations) to accomplish typed array hinting, at least with PHP7. (I didn't test on earlier versions).
Example:
class Foo {
public function test(){
echo "foo";
}
};
class Bar extends Foo {
//override parent method
public function test(){
echo "bar";
}
}
function test(Foo ...$params){
foreach($params as $param){
$param->test();
}
}
$f = new Foo();
$b = new Bar();
$arrayOfFoo = [$f,$b];
test(...$arrayOfFoo);
//will output "foobar"
The Limitations:
This isn't technically a solution, as you aren't really passing a typed array. Instead, you use the array unpacking operator1 (the "..." in the function call) to convert your array to a list of parameters, each of which must be of the type hinted in the variadic declaration2 (which also employs an ellipsis).
The "..." in the function call is absolutely necessary (which isn't surprising, given the above). Trying to call
test($arrayOfFoo)in the context of the above example will yield a type error, as the compiler expects parameter(s) of foo, not an array. See below for an, albeit hacky, solution to pass in an array of a given type directly, while preserving some type-hinting.
Variadic functions may only have one variadic parameter and it must be the last parameter (since otherwise how might the compiler determine where the variadic parameter ends and the next begins) meaning you couldn't declare functions along the lines of
function test(Foo ...$foos, Bar ...$bars){ //... }or
function test(Foo ...$foos, Bar $bar){ //... }
An Only-Slightly-Better-Than-Just-Checking-Each-Element Alternative:
The following procedure is better than just checking the type of each element insofar as (1) it guarantees the parameters used in the functional body are of the correct type without cluttering the function with type checks, and (2) it throws the usual type exceptions.
Consider:
function alt(Array $foos){
return (function(Foo ...$fooParams){
//treat as regular function body
foreach($fooParams as $foo){
$foo->test();
}
})(...$foos);
}
The idea is define and return the result of an immediately invoked closure that takes care of all the variadic / unpacking business for you. (One could extend the principle further, defining a higher order function that generates functions of this structure, reducing boilerplate). In the above example:
alt($arrayOfFoo) // also outputs "foobar"
The issues with this approach include:
(1) Especially to inexperienced developers, it may be unclear.
(2) It may incur some performance overhead.
(3) It, much like just internally checking the array elements, treats the type checking as an implementational detail, insofar as one must inspect the function declaration (or enjoy type exceptions) to realize that only a specifically typed array is a valid parameter. In an interface or abstract function, the full type hint could not be encoded; all one could do is comment that an implementation of the above sort (or something similar) is expected.
Notes
[1]. In a nutshell: array unpacking renders equivalent
example_function($a,$b,$c);
and
example_function(...[$a,$b,$c]);
[2]. In a nutshell: variadic functions of the form
function example_function(Foo ...$bar){
//...
}
can be validly invoked in any of the following ways:
example_function();
example_function(new Foo());
example_function(new Foo(), new Foo());
example_function(new Foo(), new Foo(), new Foo());
//and so on