I'm looking for a working solution, to iterate over a mongodb PersistentCollection in symfony2. Unfortunately this seems not to work? Symfony ignores the next() function!
while (($animal = $zooAnimals->next()) !== false) {
$color = $animal->getColor();
print_r($color); die; // Test and die
}
print_r('Where are the animals?'); die; // << Current result
Reference: Doctrine\ODM\MongoDB\PersistentCollection
This is not Symfony's "fault". This is a misunderstanding of how to iterate over an object. There are several ways to handle this for your use case. Here are some
Use a foreach!
Your PersistentCollection implements Collection which implements IteratorAggregate which implements Traversable (long way heh?).
An object which implements interface Traversable can be used in a foreach statement.
IteratorAggregate forces you to implement one method getIterator which must return an Iterator. This last also implements Traversable interface.
Usage of an iterator
Iterator interface forces your object to declare 5 methods in order to be used by a foreach
class MyCollection implements Iterator
{
protected $parameters = array();
protected $pointer = 0;
public function add($parameter)
{
$this->parameters[] = $parameter;
}
/**
* These methods are needed by Iterator
*/
public function current()
{
return $this->parameters[$this->pointer];
}
public function key()
{
return $this->pointer;
}
public function next()
{
$this->pointer++;
}
public function rewind()
{
$this->pointer = 0;
}
public function valid()
{
return array_key_exists($this->pointer, $this->parameters);
}
}
You can use any class which implements Iterator it like this - Demo file
$coll = new MyCollection;
$coll->add('foo');
$coll->add('bar');
foreach ($coll as $key => $parameter) {
echo $key, ' => ', $parameter, PHP_EOL;
}
Use iterator with a while
In order to use this class like a foreach. Methods should be called this way - Demo file
$coll->rewind();
while ($coll->valid()) {
echo $coll->key(), ' => ', $coll->current(), PHP_EOL;
$coll->next();
}
Simple solution:
1 Convert your PersistentCollection to an array first
$zooAnimalsArray = $zooAnimals->toArray();
2 Handle the array classically like you would with any PHP arrays.
Note This has the advantage of creating code that doesn't depend too much on your database (in case you wish one day to switch to a relational database), you wouldn't have to rewrite everything.
Works to me!
$collection = new ArrayCollection();
$collection->add('Laranja');
$collection->add('Uva');
$collection->add('Morango');
do {
print_r($collection->current());
} while ($collection->next());
This is my solution,
$zooAnimals->getIterator();
while ($animal = $zooAnimals->current()) {
echo $animal->getColor();
$zooAnimals->next();
}
Related
The clean code says, that is not recommended to initialize objects, use if statement or other things in the __constructor.
I have a class in which I used elements in the constructor which are not allowed.
How to rebuild it to conform to the rules?
I searched on google! But I do not really understand and I hope that I will succeed in understanding with this particular example.
The full code is also available on github: https://github.com/KoreLewi/21-blackjack-game
public function __construct(array $Cards = array())
{
if (empty($Cards)) {
$Cards = $this->initEnglishDeck();
}
parent::__construct($Cards);
}
public function initEnglishDeck()
{
$arrCards = array();
foreach ($this->suits as $suit) {
foreach ($this->cards as $card) {
$arrCards[] = new Card($suit, $card);
}
}
return $arrCards;
}
The full code is also available on github: https://github.com/KoreLewi/21-blackjack-game
The pattern is Dependency Injection rather than initialising your dependencies internaly.
One way to "fix" your code is to have a CardDeck Interface and multiple (or just in this case) a EnglishDeck class which implements CardDeck.
And in all the classes which require a card deck you inject it in the constructor like this:
class Game {
/**
* #var CardDeck
*/
private $cardDeck
public function __construct(CardDeck $cardDeck) {
$this->cardDeck = $cardDeck
}
}
In that case your Game class would still work even if you decide it to pass him another type of CardDeck, e.g. FrenchDeck which would also implement the CardDeck interface.
You could:
Move the if statement into the initEnglishDeck() function.
public function __construct(array $Cards = array()) {
$Cards = $this->initEnglishDeck($Cards);
parent::__construct($Cards);
}
public function initEnglishDeck($cards = array()) {
if(!empty($cards)) return $cards;
$arrCards = array();
foreach ($this->suits as $suit) {
foreach ($this->cards as $card) {
$arrCards[] = new Card($suit, $card);
}
}
return $arrCards;
}
I am trying to add functions to class from a separate file, I wonder if this could be possible!
$mClass = new MyClass();
$mClass->new_Functions[0](10); // Is there a way to have it in this form?
class myClass
{
private $Pvar = 5;
$new_Fcuntions;
function __construct()
{
include('additional.functions.php');
$arr = get_defined_functions();
$this->new_Functions = $arr['user'];
// trying to call the function with parameter 10
call_user_func(array($this, $this->new_Functions[0]), 10);
}
}
[additional.functions.php] file
function operate($y)
{
return $this->Pvar * $y;
}
----- Edited ------- as it wasn't clear!
"additional.functions.php" is a module and there will be multiple modules to be added to the application, and every module could have more than single function and modules could call one another!
additional.functions.php [module file]
function operate($y)
{
return $this->Pvar * $y;
}
function do-more($foo)
{
return $this->operate(20) + $foo;
}
another.functions.php [another module]
function do-another($foo)
{
return $this->do-more(30) - $foo;
}
function add($foo, $bar)
{
return $foo + $bar;
}
appreciate every participation, its been a while since I am trying to maneuver around with it!
Is this possible or should I give up!
It looks to me like you are looking for Traits, which are a new feature as of PHP 5.4.0. Using traits, you can have snippets of code "mixed in" to other classes, a concept known as "horizontal reuse".
If you are not looking for traits, it's possible that you could do what you wanted with Runkit, however I would suggest staying as far away from it as possible, if you are not genuinely interested in PHP internals as well.
In any event, whatever you are trying to do is very interesting
I got it to work with dependency injection. The pvar has to be public or create a __get method to return the private variable. I also used the function name because it seems cleaner to me to use it via name rather than it's position in the list but if you want to keep that then just put $key where you see $value from the line: $this->function_list[$value] = ...
function operate($y, $that)
{
return $that->Pvar * $y;
}
class Example {
public $function_list = array();
private $Pvar = 5;
public function __construct()
{
$list = get_defined_functions();
$that = $this;
foreach ($list['user'] as $key => $value) {
$this->function_list[$value] = function() use ($value, $that) {
print call_user_func_array($value, array_merge(func_get_args(), array($that )));
};
}
}
public function __get($key)
{
if (isSet($this->$key)) {
return $this->$key;
} else {
throw new \Exception('Key "'.$key.'" does not exist');
}
}
}
$Ex = new Example();
$Ex->function_list['operate'](10);
If you want to extend MyClass from your modules (and not to initialize it, like in your example code), than you could do it in a way like this:
<?php
namespace modules\MyModuleA;
class MyClassExtension
{
private $MyObject;
public function __construct(\MyClass $MyObject)
{
$this->MyObject = $MyObject;
}
public function doSomething($anyParameter)
{
return $this->MyObject->doSomethingElse($anyParameter * 5, 42, 'foo');
}
}
And MyClass:
<?php
class MyClass extends \Extensible
{
// some code
}
abstract class Extensible
{
private $extensions = [];
public function extend($extension)
{
$this->extensions[] = $extension;
}
public function __call($methodName, $parameters)
{
foreach ($this->extensions as $Extension) {
if (in_array($methodName, get_class_methods($Extension))
return call_user_func_array([$Extension, $methodName], $parameters);
}
throw new \Exception('Call to undefined method ' . $methodName . '...');
}
public function hasExtension($extensionName)
{
return in_array($this->extensions, $extensionName);
}
}
And put it all together:
<?php
$moduleNames = ['MyModuleA', 'MyModuleB'];
$MyObject = new \MyClass;
foreach ($moduleNames as $moduleName) {
$className = '\\modules\\' . $moduleName . '\\MyClassExtension';
$module = new $className($MyObject);
$MyObject->extend($module);
}
// Now you can call a method, that has been added by MyModuleA:
$MyObject->doSomething(10);
You should add an interface for the extension classes of course...
The problem is: What happens if any code in your application calls a method of $MyObject, that is not there, because the module has not been loaded. You would always have to check if ($MyObject->hasExtension('ModuleA')) { ... }, but, of course, the application shouldn't be aware of any module. So I would not design an application in such a way.
I would suggest to use traits (mix-ins). See PHP reference
If you can have another class in that file instead of file with functions
- the best solution will be Traits
http://php.net/manual/en/language.oop5.traits.php
or using inheritance
If you move that code to class you can avoid a lot of unnecessary code. I mean:
include('additional.functions.php');
$arr = get_defined_functions();
$this->new_Functions = $arr['user'];
// trying to call the function with parameter 10
call_user_func(array($this, $this->new_Functions[0]), 10);
It'll be e.g.:
class myClass extends MyBaseClassWithMyAwesomeFunctions
{
private $Pvar = 5;
}
Maybe this approach helps you:
In the files with the additional functions, don't define named functions, but return a closure, that expects (at least) the object (instance of MyClass) as parameter:
<?php
// additional.functions.php
return function ($myObject) {
$Object->multiplyPvar($myObject->getTheNumber());
$Object->doSomethingElse(42, 'foo');
};
The client, that builds MyClass collects those functions from the files into the array:
<?php
$files = [
'/path/to/my/additional.functions1.php',
'/path/to/my/additional.functions2.php'
];
$initFunctions = [];
foreach ($files as $path)
$initFunctions[] = include $path;
$MyObject = new \MyClass($initFunctions);
The constructor then calls those functions:
<?php
class MyClass
{
public function __construct(array $additionalInitFunctions)
{
foreach ($additionalInitFunctions as $additionalInitFunction)
$additionalInitializerFunction($this); // you can also add parameters of course
}
}
This way the class keeps very well testable as well as the function files. Maybe this could help you in any way. You should never ever think about modifying the internal (private) state of an object directly from any code from outside of the class. This is not testable! Think about writing tests before you implement your code (called "test driven development"). You will see, it is not possible to test a class, if you allow any code outside of that class to modify the internal (private) state of the class instance. And you don't want to have this. If you change some internal implementation detail in your class without breaking the unit test of that class, you will anyways probably break some code in any of your additional.functions.php files and no test will tell you: "Hey: you've broken something right now".
Consider an object used to store a collection of items, but that collection may vary depending on predefined contexts.
Class Container implements IteratorAggregate (
protected $contexts; // list of associated contexts, example: array(0=>1,1=>3)
protected $contents; // array
public loadContents( $contextId ) { /* populates $this->contents*/ }
public getContexts() { /* populates $this->contexts */ }
...
public function getIterator() { return new ArrayIterator($this->contents); }
public getContextIterator() { return new contextIterator($this); }
}
The iterator looks like:
Class contextIterator {
protected $container;
protected $contexts;
protected $currentContext;
public function __construct($container) {
$this->container = $container;
$this->contexts = $container->getContexts();
$this->currentContext = 0;
}
public current() {
$this->container->loadContents( $this->key() );
return $this->contexts[ $this->key() ];
}
public function key() { return $this->currentContext; }
public function next() { $this->currentContext++; }
public function rewind() { $this->currentContext = 0; }
public function valid() { return isset( $this->contexts[ $this->key() ] ); }
}
For the few cases where each context needs to be examined iteratively, I do the following:
$myContainer = new Container();
foreach( $myContainer->getContextIterator() as $key => $value ) {
$myContainer->someMethod();
}
The above is nice and compact, but it feels dirty to me since I'm never actually using $key or $value. Is using the iterator overkill? Further, should an iterator ever change the state/contents of the object it is iterating?
The above is nice and compact, but it feels dirty to me since I'm never actually using $key or $value.
You have not shown the inners of getContextIterator() so it's hard to make concrete suggestions. Generally it's possible to create iterate-able objects in PHP by implementing the OuterIterator interace or by just implementing the Iterator interface. Both interfaces are predefined and you then can use your object with next(), foreach etc.
I assume you've implemented something like OuterIterator. If you implement OuterIterator instead, you will get some speed benefit AFAIK.
Is using the iterator overkill?
No, won't say so. Iterators are very good for collections as you said you have one. I just would change it into a SPL iterator though.
Further, should an iterator ever change the state/contents of the object it is iterating?
Well actually each iterator does, at least for the internal pointer of the iteration. But I think that was not your concern, but might already lighten up.
So even for "more" changes inside the object you're iterating over, it's perfectly okay that it changes as long as it's clear what it does. Counter-Example: if you iterate over an array and it would shuffle elements each time the iteration goes one step ahead would not be useful.
But there are other cases where this is totally valid and useful. So decide on what's done, not with a general rule.
PLEASE CHECK ANSWERS by VolkerK too, he provided another solution, but I can't mark two posts as answer. :(
Good day!
I know that C# allows multiple iterators using yield, like described here:
Is Multiple Iterators is possible in c#?
In PHP there is and Iterator interface. Is it possible to implement more than one iteration scenario for a class?
More details (EDIT):
For example I have class TreeNode implementing single tree node. The whole tree can be expressed using only one this class. I want to provide iterators for iterating all direct and indirect children of current node, for example using BreadthFirst or DepthFirst order.
I can implement this Iterators as separate classes but doing so I need that tree node should expose it's children collection as public.
C# pseudocode:
public class TreeNode<T>
{
...
public IEnumerable<T> DepthFirstEnumerator
{
get
{
// Some tree traversal using 'yield return'
}
}
public IEnumerable<T> BreadthFirstEnumerator
{
get
{
// Some tree traversal using 'yield return'
}
}
}
Yes, you can.
foreach(new IteratorOne($obj) as $foo) ....
foreach(new IteratorTwo($obj) as $bar) .....
Actually, as long as you class implements Iterator, you can apply any arbitrary IteratorIterator to it. This is a Good Thing, because applied meta iterators are not required to know anything about the class in question.
Consider, for example, an iterable class like this
class JustList implements Iterator
{
function __construct() { $this->items = func_get_args(); }
function rewind() { return reset($this->items); }
function current() { return current($this->items); }
function key() { return key($this->items); }
function next() { return next($this->items); }
function valid() { return key($this->items) !== null; }
}
Let's define some meta iterators
class OddIterator extends FilterIterator {
function accept() { return parent::current() % 2; }
}
class EvenIterator extends FilterIterator {
function accept() { return parent::current() % 2 == 0; }
}
Now apply meta iterators to the base class:
$list = new JustList(1, 2, 3, 4, 5, 6, 7, 8, 9);
foreach(new OddIterator($list) as $p) echo $p; // prints 13579
foreach(new EvenIterator($list) as $p) echo $p; // prints 2468
UPDATE: php has no inner classes, so you're kinda out of luck here, without resorting to eval, at least. Your iterators need to be separate classes, which are aware of the baseclass structure. You can make it less harmful by providing methods in the base class that instantiate iterators behind the scenes:
class TreeDepthFirstIterator implements Iterator
{
function __construct($someTree).....
}
class Tree
{
function depthFirst() { return new TreeDepthFirstIterator($this); }
....
}
foreach($myTree->depthFirst() as $node).....
Another option is to use lambdas instead of foreach. This is nicer and more flexible, requires php5.3 though:
class Tree
{
function depthFirst($func) {
while($node = .....)
$func($node);
.....
$myTree->depthFirst(function($node) {
echo $node->name;
});
For your purpose it might be sufficient to have a "mode" flag in your class, so the user can choose whether to have a bread-first or a depth-first iterator.
class Tree {
const TREE_DEPTH_FIRST = 0;
const TREE_BREADTH_FIRST = 0;
protected $mode;
protected $current;
public function __construct($mode=Tree::TREE_DEPTH_FIRST) {
$this->mode = $mode;
}
public function setMode($mode) {
...
}
public function next() {
$this->current = advance($this->current, $this->mode);
}
....
}
(and the short answer to your initial question: no php doesn't have the syntactic sugar of yield return and it doesn't have inner private classes, i.e. whatever you would need the iterator you're returning to do with the "original" object has to be exposed to the outside world. So you'd probably end up "preparing" all elements for an iterator object like ArrayIterator, the very thing you avoid by using yield)
This code shows you how to add multiple iterators in a class.
class TreeNode {
public function getOddIterator () {
return new OddIterator($this->nodes);
}
public function getEvenIterator () {
return new EvenIterator($this->nodes);
}
}
You can have multiple Iterators. The key idea in the Iterator is to take the responsibility for access and traversal out of the list object and put it into an iterator object. So if you want to have multiple Iterators with the same list or different lists; there's no problem.
You can find four different PHP examples here:
http://www.php5dp.com/category/design-patterns/iterator/
You can also use them with Linked Lists.
Cheers,
Bill
I'm using PHPUnit but find it difficult to make it create good mocks and stubs for objects used as datastore.
Example:
class urlDisplayer {
private $storage;
public function __construct(IUrlStorage $storage) { $this->storage = $storage; }
public function displayUrl($name) {}
public function displayLatestUrls($count) {}
}
interface IUrlStorage {
public function addUrl($name, $url);
public function getUrl($name);
}
class MysqlUrlStorage implements IUrlStorage {
// saves and retrieves from database
}
class NonPersistentStorage implements IUrlStorage {
// just stores for this request
}
Eg how to have PHPUnit stubs returning more than one possible value on two calls with different $names?
Edit: example test:
public function testUrlDisplayerDisplaysLatestUrls {
// get mock storage and have it return latest x urls so I can test whether
// UrlDisplayer really shows the latest x
}
In this test the mock should return a number of urls, however in the documentation I only how to return one value.
Your question is not very clear - but I assume you are asking how to use phpunit's mock objects to return a different value in different situations?
PHPUnit's mock classes allow you specify a custom function (ie: a callback function/method) - which is practically unlimited in what it can do.
In the below example, I created a mock IUrlStorage class that will return the next url in its storage each time it is called.
public function setUp()
{
parent::setUp();
$this->fixture = new UrlDisplayer(); //change this to however you create your object
//Create a list of expected URLs for testing across all test cases
$this->expectedUrls = array(
'key1' => 'http://www.example.com/url1/'
, 'key2' => 'http://www.example.net/url2/'
, 'key3' => 'http://www.example.com/url3/'
);
}
public function testUrlDisplayerDisplaysLatestUrls {
//Init
$mockStorage = $this->getMock('IUrlStorage');
$mockStorage->expects($this->any())
->method('getUrl')
->will( $this->returnCallback(array($this, 'mockgetUrl')) );
reset($this->expectedUrls); //reset array before testing
//Actual Tests
$this->assertGreaterThan(0, count($this->expectedUrls));
foreach ( $this->expectedUrls as $key => $expected ) {
$actual = $this->fixture->displayUrl($key);
$this->assertEquals($expected, $actual);
}
}
public function mockGetUrl($name)
{
$value = current($this->expectedUrls);
next($this->expectedUrls);
//Return null instead of false when end of array is reached
return ($value === false) ? null : $value;
}
Alternatively, sometimes it is easier to simply create a real class that mocks up the necessary functionality. This is especially easy with well defined and small interfaces.
In this specific case, I would suggest using the below class instead:
class MockStorage implements IUrlStorage
{
protected $urls = array();
public function addUrl($name, $url)
{
$this->urls[$name] = $url;
}
public function getUrl($name)
{
if ( isset($this->urls[$name]) ) {
return $this->urls[$name];
}
return null;
}
}
?>
Then in your unit test class you simply instantiate your fixture like below:
public function setUp() {
$mockStorage = new MockStorage();
//Add as many expected URLs you want to test for
$mockStorage->addUrl('name1', 'http://example.com');
//etc...
$this->fixture = new UrlDisplayer($mockStorage);
}