My question is what is a neat way to obtain an array of objects from an array of classes.
The array of classes I get by using array_filter() on get_declared_classes().
EDIT:
My own attempts were pretty correct, the thing was I forgot to return value of in_array() in callback function :
$classes_array = array_filter(
get_declared_classes(),
function($class_name){
return in_array('IItem', class_implements($class_name));
}
$objects_array;
foreach($classes_array as $class){
$objects_array[] = new $class();
}
You can use array_map(), and refer to Creating PHP class instance with a string
$objects = array_map(function($v){
return new $v();
}, get_declared_classes());
Related
I am not fully understanding Laravel Collections.
I need to know how save external values while iterating through a Lavavel Collection using the each(function(n){})
For example:
static public myFunction($laravelCollection) ={
$arr=[];
$laravelCollection->each(function($a){
$arr[]=$a
});
return $arr
}
...
$exampleArr = SomeClass::myFunction($aCollection);
var_dump($exampleArr);
//desired results: the var_dump of the collection
It seams that $arr inside of the each function is local to the function. How can I accomplish the above? I realize that if it was NOT a static function, I could simply use a $this->arr instead, but I need to do the above using a static function.
Modifying a variable inside a laravel collection, you will have to use use() method with reference &.
$arr = [];
$laravelCollection->each(function($a) use(&$arr) {
$arr[] = $a;
});
Or even better, since you are simply converting your collection into an array:
$arr = $laravelCollection->toArray();
Check out the collection docs.
I have a class called Collection which stores objects of same type.
Collection implements array interfaces: Iterator, ArrayAccess, SeekableIterator, and Countable.
I'd like to pass a Collection object as the array argument to the array_map function. But this fails with the error
PHP Warning: array_map(): Argument #2 should be an array
Can I achieve this by implementing other/more interfaces, so that Collection objects are seen as arrays?
The array_map() function doesn't support a Traversable as its array argument, so you would have to perform a conversion step:
array_map($fn, iterator_to_array($myCollection));
Besides iterating over the collection twice, it also yield an array that will not be used afterwards.
Another way is to write your own map function:
function map(callable $fn)
{
$result = array();
foreach ($this as $item) {
$result[] = $fn($item);
}
return $result;
}
Update
Judging by your use-case it seems that you're not even interested in the result of the map operation; therefore it makes more sense to use iterator_apply().
iterator_apply($myCollection, function($obj) {
$obj->method1();
$obj->method2();
return true;
});
array_map wants, as the name suggests, arrays. It's not called iterator_map after all. ;)
Apart from iterator_to_array(), which produces a potentially large temporary array, there's no trick to make iterable objects work with array_map.
The Functional PHP library has a map implementation which works on any iterable collection.
If you're not interested in creating a new array that is a function mapped over the original array, you could just use a foreach loop (because you implement Iterator).
foreach($item in $myCollection) {
$item->method1();
$item->method2();
}
if you actually want to use map, then I think you'll have to implement your own. I would suggest making it a method on Collection, eg:
$mutatedCollection = $myCollection->map(function($item) {
/* do some stuff to $item */
return $item;
});
I would ask yourself if you really want to use map or do you really just mean foreach
I came up with the following solution:
//lets say you have this iterator
$iterator = new ArrayIterator(array(1, 2, 3));
//and want to append the callback output to the following variable
$out = [];
//use iterator to apply the callback to every element of the iterator
iterator_apply(
$iterator,
function($iterator, &$out) {
$current = $iterator->current();
$out[] = $current*2;
return true;
},
array($iterator, &$out) //arguments for the callback
);
print_r($out);
This way, you can generate an array without iterating twice as you would to with the approach like:
$iterator = new ArrayIterator(array(1,2,3));
$array = iterator_to_array($iterator); //first iteration
$output = array_map(function() {}, $array); //second iteration
Good luck!
I just stumbled upon this question and I managed to cast the collection to an array to make it work:
array_map($cb, (array) $collection);
disclaimer For the original question this might not be a suitable option but I found the question while looking to solve a problem which I solved with this solution. I would recommend using a custom iterator map where possible/viable.
another option is to do something like this:
foreach($collection as &$item) {
$item = $cb($item);
}
which will mutate the underlying collection.
EDIT:
It has been pointed out that casting to an array can have unwanted side effects. It would be better to add a method to your collection to return the array from the iterator, and traverse that, or otherwise add a map method which accepts a callback and run a loop on the underlying iterator.
First code and then the question:
class MyArray
{
private $arrayRef;
function __construct(&$array){
$this->arrayRef = $array;
}
function addElement($newElement){
$this->arrayRef[] = $newElement;
}
function print(){
print_r($this->arrayRef);
}
}
$array = ['first', 'second'];
$arrayObject = new MyArray($array);
$arrayObject->addElement('third');
print_r($array); // prints array containing 2 elements
echo '<br/>';
$arrayObject->print(); // prints array containing 3 elements
Class member $arrayRef, in this example doesn't work as a reference to another array provided in constructor. Argument in constructor is passed by reference, but I guess that doesn't make member $arrayRef also a reference to that array as well.
Why doesn't it work like that and how to make it work?
If you still don't get what I mean: first print_r prints array containing 2 elements, even thought it may be expected to contain 3.
When I pass third element to $arrayObject via addElement() I also want it to be added in the $array that I passed to constructor of class.
The answer is actually quite simple. Yes, you pass the array by reference via &$array but this reference gets lost when you assign/copy it to the member variable. To keep the reference, you can use the =& operator like so
$this->arrayRef =& $array;
See it work in this fiddle. You can read more about it in this question/answer (just look for reference).
Beware not to use &= (which does a bitwise operation) instead of =& (which assigns by reference).
I have an array whose items are of a certain object type, let it be my_object.
The class defining the my_objects has a function that I want to use to filter the array. How can I specify that function when calling array_filter?
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
}
$array=array($my_object1, $my_object2, ....);
$filtered=array_filter($array,'filter_function');//obviously does not work
my_object1 , my_object2 , ... are all instances of my_class and I want that the
$my_object1->filter_function()
$my_object2->filter_function()
,.....
be called for filtering the array.
If you want to filter the array based on return value of each individual object's filter_function method call, you could simply:
array_filter($array, function($obj) { return $obj->filter_function(); });
No need to clutter the original class with static methods as in Mark's answer.
You need to indicate the object as well as the method in your callback, using an array syntax as shown in the php docs for callbacks
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
}
$array = array($my_object1, $my_object2, ....);
$classFilter = new my_class();
$filtered = array_filter($array,[$classFilter, 'filter_function']);
In this case, you need to create an instance first, then use that instantiated object as the first element in the callback, and the method name as the second element
EDIT
However, if you're trying to filter this collection of my_class objects based on whether individual objects have the exclude set, then you need to have a filter method for the collection:
class my_class{
private $exclude;
public filter_function(){
return !$this->exclude;
}
public static filter_collection($value){
return $value->filter_function();
}
}
$array = array($my_object1, $my_object2, ....);
$filtered = array_filter($array,['my_class', 'filter_collection']);
I've been looking to a solution to my problem for a while without success so I'm asking here.
How can we return a json-encoded result on an array of objects (or just an object) containing private properties ?
Indeed, when you use json_encode($myObject), it won't display the private or protected properties, which are present everywhere in the model when using Symfony...
I'm surprised I couldn't find any method like json_encode that would call getters instead of properties themselves.
Any idea ?
EDIT
In that case I would rather do a unique function that looks like :
public function toArray() {
$vars = get_object_vars($this);
$result = array();
foreach ($vars as $key => $value) {
if (is_object($value)) {
$result[$key] = toArray($value);
} else {
$result[$key] = $value;
}
}
return $result;
}
in order to avoid rewriting every property name everytime...
But anyway I think I'll just create an array containing the vars I need, so that I won't touch the model (which is generated code).
Have you try GetSetMethodNormalizer ?
http://api.symfony.com/2.0/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.html
Ex. https://stackoverflow.com/a/6709828/520114
Right now there is no way for this. Only php serialize/unserialize handles the true serialisation of objects.
You'll have to implement them yourselve, or rather let objects return their json values themselves.
You will have to implement your own method toArray() where you expose all your private values in an array:
public function toArray()
{
return array(
'property1' => $this->myproperty1,
'property2' => $this->myproperty2
);
}
And call it like this:
json_encode(MyObject->toArray());
[Edit: this question is not about doctrine, but since you mention both symfony2 and the model, you can consider using Array Hydration for your model: http://www.doctrine-project.org/docs/orm/2.0/en/reference/dql-doctrine-query-language.html#array-hydration ]