Is it possible to class cast? - php

I'm am a newb with the whole class inheritance in general but I am a bit more confused with php.
I would like to have the following:
class Base
{
//some fields and shared methods...
}
class Node
{
private $children = array();
public function getChildren()
{
...
}
public function addChild($item)
{
$children[] = $item;
}
public function sum()
{
}
}
I want $item to be either another Node or a Leaf:
class Leaf extends Base
{
private $value;
public getValue()
{
}
public setValue($someFloatNumber)
{
$this->value = $someFloatNumber;
}
}
For public sum(), I want something like:
$sum = 0;
foreach ($children as $child)
{
switch(gettype($child))
{
case "Node":
$sum+= ((Node) $child)->sum();
break;
case "Leaf":
$sum+= ((Leaf) $child)->getValue();
break;
}
}
return $sum;
Not sure how to do the cast. Also would the array store the type of the added $item?

This is not proper OOP. Try this instead:
Add method sum to Base (abstract if you don't want to implement). Implement this same method sum for Leaf, which would simply return it's getValue. Then you can simply call sum on both types, thus no need for case, or to know it's type and so on:
foreach ($children as $child) {
$sum += $child->sum();
}
This is called polymorphism and it's one of the basic concepts of object oriented programming.
To also answer your question, you can hint type locally in Netbeans and Zend Studio (and probably other editors) with:
/* #var $varName Type_Name */

You're asking about hinting but then, in your code, you actually try to do a cast. Which is not necessary and not possible in that way.
Hinting example:
private function __construct(Base $node) {}
Which ensures that you can only pass an instance of Base or inheriting classes to the function.
Or if it's important for working in your IDE, you can do:
$something = $child->someMethod(); /* #var $child Base */
Which will make sure, your IDE (and other software) know that $child is of the type Base.
Instead of casting you could just use is_a like that:
if (is_a($child, 'Node') {}
else (is_a($child, 'Leaf') {}
But to be honest, it rather seems like you should refactor your code. I don't think it a good idea that a leaf is any different from a node. A leaf is just a node that doesn't have any children, which you can test anytime with $node->hasChildren() and even set and unset a leaf flag, if you need to.

Related

Class properties as Array instead of variables

I'm starting to work with classes in PHP.
I have been reading and I noticed PHP is all about arrays.
So I was wondering if it would be a good practice to use the class properties inside array and naming them after keys.
Like this:
private $prefix;
private $name;
public function setPrefix($p)
{
$this->prefix = $p;
}
public function getPrefix()
{
return $this->prefix;
}
public function setName($n)
{
$this->name = $n;
}
public function getName()
{
return $this->name;
}
That's the common way of doing this.
But instead do it like this:
private $data = array();
public function setData($property, $value)
{
$this->data[$property] = $value;
}
public function getData($property)
{
return $this->data[$property];
}
Would this be better than the common way? I believe that would be a generic class structure for any database table.
Would this be better than the common way?
NO. And in fact it have drawbacks.
It removes the public, protected and private encapsulation of your properties (which is in the essence of oop).
Adds a layer over every variable access. I don't really know the internals of php, but I really don't think it could be faster than native properties. (although the difference is probably absolutely irrelevant to any script)
IDE's won't be able to complete your code when accessing properties.
It can have it's uses, if your class is a container which needs to have an array of internal data, in which case you would class container implements ArrayAccess and use it like an array, instead of global get/set methods. Here the documentation for ArrayAccess()
$obj = new container();
$obj['key'] = "value";
echo $obj['key'];
Bottom line
Why try and reinvent the wheel? A property is a property. There is no logical or semantical improvement in wrapping every property inside another property. It's obsfucating everything. It won't be faster, it won't be clearer, it removes the oop concepts from your properties and it's just going against the current of using objects in the first place.
About easier database management
If you really want to easily pass an array to a prepared statement, you can get the properties of an object with get_object_vars($obj), no need to put them in an array before for this very purpose. Moreover, as noted by Cypher, you won't be able to use the built-in fetchObject() method, which completely nullify the time you will not have gained by having an easier time querying the database.
This will make it easy to automate DB Operations.
But will make it hard for to use the object by humans.
Yii(2) uses this setup as part of there ActiveRecords but extend it by
defining the properties as a comment
/**
* #property int $id
* #property string $name
*/
class SomeClass extends AbstractModel
And also implements magic methods: __get(), __set()` so you can easily set and get properties like this:
class AbstractModel{
public function __get($name){
if(isset($this->data[$name])){
return $this->data[$name];
}else{
throw new Exception("Undefined or property '$name'");
}
}
public function __set($name, $value){
if(isset($this->data[$name])){
return $this->data[$name] = $value;
}else{
throw new Exception("Undefined or property '$name'");
}
}

OOP approach for wrapping subclasses of database rows

Let's say I want to store dogs in a database table with each dog having its own subclass in PHP.
Basically I want to avoid storing/listing the subclass names in different places in the code. What would be a good OOP approach for that?
abstract class Dog {
protected $data;
public function __construct($data) {
$this->data = $data;
}
public function name() {
return $this->data["name"];
}
abstract public function breed();
}
class GermanShepherd extends Dog {
public function breed() {
return _("German Shepherd");
}
}
class BullDog extends Dog {
public function breed() {
return _("Bulldog");
}
}
Now I have this class that handles groups of objects (i.e. dogs):
class Dogs {
public static function getDogs() {
// ...
$ret = array();
while ($row = mysql_fetch_assoc()) {
switch ($row["type"]) { // I could do this using a lookup array
case "shepherd": $dog = "GermanShepherd"; break;
case "bulldog": $dog = "Bulldog"; break;
}
$ret[] = new $dog($row);
}
return $ret;
}
}
And I would like to use this class to get the dog types in my view (especially for an add dog form), instead of listing the class names:
?><form><select name="type"><?php
foreach (array("GermanShepherd", "Bulldog") as $dog) { // here I would like to do avoid listing the class names again
?><option value="<?=$dog ?>"><?php
$d = new $dog; // actually I can't instantiate the class here because I don't have any data at this point
echo $d->name();
?></option><?php
}
?></select></form><?php
I would like to incorporate this into the Dogs class, something along the lines of this:
class Dogs {
private static $dogs = array(
"shepherd" => "GermanShepherd",
"bulldog" => "Bulldog",
);
public static function getDogs() {
// ...
$ret = array();
while ($row = mysql_fetch_assoc()) {
$dog = self::$dogs[$row["type"]];
$ret[] = new $dog($row);
}
return $ret;
}
public static function getDogTypes() {
return array_values(self::$dogs);
}
}
?><form><select name="type"><?php
foreach (Dogs::getDogTypes() as $dog) {
?><option value="<?=$dog ?>"><?php
$d = new $dog; // here I still need to instantiate the class and I don't have any data to provide it with
echo $d->name();
?></option><?php
}
?></select></form><?php
This would somewhat work so far, but what if I need more class specific information, for example when I have more fields specific to a dog type?
foreach (Dogs::getDogTypes() as $dog) {
$d = new $dog; // instantiate again?
foreach ($d->formFields() as $f) { // I wouldn't do it like this, just putting this here for demonstrative purposes
echo $f;
}
}
I think part of the problem lies in the fact that I need to be able to use my classes with and without database data: Everything seems very reasonable when I have the data from the database table, but I also need the data when I generate the form when creating a new dog.
Thanks for your ideas!
First make use of Interfaces. This will show you that having more specific interfaces (different class methods and properties per subclass) will make you need to deal with them differently in concrete. So they will show you where the deficiencies are and will enable you to streamline your objects into something more re-useable.
As long as your objects are only storing some data, use a data transfer object instead - which is of any "type". So you don't need to deal with type. However, you can use StdClass or Array for that as well if you want to keep it basic. The plus-side is: You don't need to actually write that much code.
In case it's not sufficient (as it will be), only add the code when you need to. Should keep things more simple in the long run then. So start with a basic data transfer object class and build upon it.
So use the classes you write to separate concerns, not to interweave the concerns. Encapsulate what varies, so your code can actually benefit from your design.
I think the static array in your Dogs class is quite an acceptable solution. It doesn't cover for the instantiating problem, but you can fix that with a (static) factory method. To make the instantiating even easier and more scalable, you can make sure the stored strings map to object names somehow:
$dog = 'Dog' . ucfirst( $row['type'] );
$ret[] = new $dog;
I don't think a ->getFormFields() method is a bad idea at all; when the fields differ per Dog type, it would be perfectly valid OO to incorporate that in the object!
What about storing your dogs in a 2D array?
while ($row = mysql_fetch_assoc()) {
switch ($row["type"]) { // I could do this using a lookup array
case "shepherd":
$dog = "GermanShepherd";
break;
case "bulldog":
$dog = "Bulldog";
break;
} // switch
$ret[$row["type"]][] = new $dog($row);
} // while

Is changing an objects state/contents appropriate Iterator usage (php)

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.

Syntax choices for accessing child objects

I'm wondering which is semantically and technically most optimal of my choices here. I've created a simple object registry class, but the method of object access has me wondering what's best. I'm currently using the first variation:
//the Registry methods can chain, each returning a self reference
$registry = Registry::getInstance()->register('myObject', new Object);
//accessing a registered object method
//in various possible ways
Registry::getInstance()->myObject->method(); //1
Registry::getInstance()->use('myObject')->method(); //2
$registry('myObject')->method(); //3
The first variation uses __get() magic, keeping with the fluent syntax.
The second uses the 'getter' method use().
The third uses __invoke() magic, which has been suggested, but I am not too fond of.
I'm just curious to know if anyone has insight, or suggestions towards using any (or none) of these options. The reason for using a Registry class in my case is to provide pseudo-globalization of key objects, for use in nested closures (declaring them with use every time is cumbersome)
This is somewhat related to my other question, at PHP closures and implicit global variable scope
Thanks in advance :)
My personal opinion is to Use a combination of your 2nd and 3rd code-example. Using both (or only your 2nd example) you can use phpDoc to maintain autocompletion.
Here's an example:
<?php
class Session {
public function register() {
}
}
/**
* #property Session $session
*/
class Registry {
private $_classes = array();
public function __set($key, $value) {
$key = (string) $key;
if ((null === $value) && isset($this->_classes[$key])) {
unset($this->_classes[$key]);
} elseif (null !== $value) {
$this->_classes[$key] = $value;
}
}
public function __get($key) {
$key = (string) $key;
if (isset($this->_classes[$key])) {
return $this->_classes[$key];
}
switch ($key) {
case 'session':
$this->_classes[$key] = new Session();
break;
}
return $this->_classes[$key];
}
}
$registry = new Registry();
$registry->session->register();
If I should give you a hint why my Registry-class does not follow the singleton-pattern ... avoid using the singleton-pattern if you want to run unit-tests. See here: http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html

Are Multiple Iterators possible in php?

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

Categories