Objects to strings, unique keys in PHP - php

I was reading around about the Observer pattern, and found a dated article. Having read through, I noticed an interesting mention in this paragraph:
The key methods to look at here are attach(), detach(), and notify(). attach() and detach() handle adding and removing observers. We use a little trick here. Objects quoted in string context resolve to a unique identifier (even if __toString() is defined). You can use this fact to build keys for an associative array. The notify() method cycles through all attached observers, calling update() on each. The UploadManager class calls notify() whenever it has something important to report on upload and on error, in this case.
Which references this example:
function attach(UploadObserver $obs) {
$this->observers["$obs"] = $obs;
}
Now as mentioned, this article is dated. Casting objects to strings of course no longer works in this manner (I run 5.3.6 on my dev box, and push it for all client projects) but I'd like to achieve similar functionality. I can only think of (something like) this:
function attach(Observer $observer){
$this->_observers[md5(serialize($observer))] = $observer;
}
function detach(Observer $observer){
unset($this->_observers[md5(serialize($observer))]);
}
I'm curious, are there any other efficient ways to achieve this; creating a unique key from the object itself.
Caveat: I don't want to get into defined keys, I use those often enough with other repositories and such, implementing __set($key, $value), etc.
Note: I understand MD5 isn't ideal.
Update: Just found spl_object_hash, and I assume this is likely my best choice, however feel free to share your thoughts.

You're right that does not work that way any longer. You might want to use some other function instead: spl_object_hash()
function attach(Observer $observer){
$this->_observers[spl_object_hash($observer)] = $observer;
}
function detach(Observer $observer){
unset($this->_observers[spl_object_hash($observer)]);
}
The serialization based approach has a design problem btw: I stops working when objects are identical by value or in other words if objects return the same serialized value, e.g. NULL. This is fully controllable by the objects themselves when they implement the Serializable interface.

Have you tried the SPL object hash function?

Alternatively you could use SplObjectStorage directly.
Like:
function __construct(...){
$this->_observers = new SplObjectStorage;
}
function attach(Observer $observer) {
$this->_observers[$observer] = $observer;
}
function detach(Observer $observer){
unset($this->_observers[$observer]);
}

Related

Check if an object has changed

Is there a more native way (e.x. a built-in function) with less userland code to check if an objects property values have changed instead of using one of those methods:
The serialize approach
$obj = new stdClass(); // May be an instance of any class
echo $hashOld = md5(serialize($obj)) . PHP_EOL;
$obj->change = true;
echo $hashNew = md5(serialize($obj)) . PHP_EOL;
echo 'Changed: '; var_dump($hashOld !== $hashNew);
Which results in:
f7827bf44040a444ac855cd67adfb502 (initial)
506d1a0d96af3b9920a31ecfaca7fd26 (changed)
Changed: bool(true)
The shadow copy approach
$obj = new stdClass();
$shadowObj = clone $obj;
$obj->change = true;
var_dump($shadowObj != $obj);
Which results in:
bool(true);
Both approaches work. But both have disadvantages compared to a non userland implementation. The first one needs CPU for serialization and hashing and the second one needs memory for storing clones. And some classes may not be cloned.
Doesn't PHP track changes at object properties? And does PHP not expose a method to make use of it?
What you are trying to do?
You are trying to compare object with itself, after some chain of "unknown" operations to check if the object has changed. If this is true, there are some logical points to observe. At first, if you want to compare object with itself, you've got only two options:
Remember the whole object state (for example hash, or just copy whole object)
Track changes over time
There is no other logical approach. Comparing memory allocations, real objects, copying objects, comparing hashes, is all in point one. Tracking changes, saving changes inside object, remembering meantime operations, inside point 2.
So in my opinion this question is sort of backing up data questions. In that case there are many, many solutions but none of them are hardcoded inside php as far as I'm concerned. Why?
The answer is simple. PHP guys have got the same problems you've got :). Because if this would be hardocded inside php, then php should run / use one of those mechanisms (1) or (2).
In that case every object that you create, and every operation you made should be written somewhere to remember every state / object / something and use them for comparison in the future.
While you need this solution, almost ~100% of websites don't. So hardcoding this inside php would made ~100% of websites work slower and your work faster ;).
PHP hypothetical solution?
The only solution (maybe built in php in the future) I can think of is making some kind of php config flag: track objects, and only if this flag is true, then run all the php mechanisms of tracking objects states. But this also mean a huge performance gap. As all the ifs (if tracking, if tracking, if tracking) are also procesor and memory time consuming.
There is also a problem, what to compare? You need to compare object with same object, but... Few minutes ago? Few operations ago? No... You must point exactly one place in code, and then point second place in code and compare object in those two places. So hypothetical auto tracking is... Kind of powerless, as there is no "key" in the object state ofer time array. I mean, even if you got magic_object_comparer function, what it should look like?
<?php
function magic_object_comparer() {} // Arguments??
function magic_object_comparer($object_before, $object_after) {} // you must save object_before somewhere...??
function magic_object_comparer($object, $miliseconds) {} // How many miliseconds?
function magic_object_comparer($object, $operations) {} // How many operations? Which operations?
magic_comparer_start($object);
// ... Few operations...
$boolean = magic_comparer_compare_from start($object);
// Same as own implementation...
?>
Sadly, you are left with own implementation...
After all, I would propose to implement some kind of own mechanism for that, and remember to use it only there, where you need it. As this mechanism will for sure be time and memory consuming. So think carefully:
Which objects you want to compare. Why?
When you want to compare them?
Does all changes need to be compared?
What is the easiest way of saving those states changes?
And after all of that, try to implement it. I see that you've got a huge php knowledge, so I'm pretty sure that you will figure out something. There are also many comments, and possible ideas in this question and discussion.
But after all maybe I explained a little why, there is no build in solution, and why there should not be one in the future... :).
UPDATE
Take a look here: http://www.fluffycat.com/PHP-Design-Patterns/. This is a great resource about php patterns. You should take a look at adapter, decorator and observer patterns, for possible elegant object oriented solutions.
While I too am looking for a very fast/faster approach, a variant of method 2 is effectively what I use. The advantage of this method is that it is (pretty) fast (in comparison to an isset()), depending on object size. And you don't have to remember to set a ->modified property each time you change the object.
global $shadowcopy; // just a single copy in this simple example.
$thiscopy = (array) $obj; // don't use clone.
if ($thiscopy !== $shadowcopy) {
// it has been modified
// if you want to know if a field has been added use array_diff_key($thiscopy,$shadowcopy);
}
$shadowcopy = $thiscopy; // if you don't modify thiscopy or shadowcopy, it will be a reference, so an array copy won't be triggered.
This is basically method 2, but without the clone. If your property value is another object (vobj), then clone may be necessary (otherwise both references will point to the same object), but then it is worth noting that it is that object vobj you want to see if has changed with the above code. The thing about clone is that it is constructing a second object (similar performance), but if you want to see what values changed, you don't care about the object itself, only the values. And array casting of an object is very fast (~2x the speed of a boolean cast of a bool) .. well, up until large objects. Also direct array comparison === is very fast, for arrays under say 100 vals.
I'm pretty sure an even faster method exists...
I can offer you another solution to the problem, In fact to detect "if an object has changed" we can use observer pattern design principles. May that way should be better for some people who want to get notify about changes in object.
Contracts/ISubject.php
<?php
namespace Contracts;
interface ISubject
{
public function attach($observer): void;
public function detach($observer): void;
public function notify(): void;
}
Contracts/IObserver.php
<?php
namespace Contracts;
interface IObserver
{
public function update($subject);
}
Subject.php
class Subject implements ISubject
{
public $state; // That is detector
private $observers;
public function __construct()
{
$this->observers = new \SplObjectStorage(); // That is php built in object for testing purpose I use SplObjectStorage() to store attach()'ed objects.
}
public function attach($observer): void
{
echo "Subject: Attached an observer.\n";
$this->observers->attach($observer);
}
public function detach($observer): void
{
$this->observers->detach($observer);
echo "Subject: Detached an observer.\n";
}
public function notify(): void
{
echo "Subject: Notifying observers...\n";
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function someYourLogic()
{
$this->state = rand(0, 10);
echo "Subject: My state has just changed to: {$this->state}\n";
$this->notify();
}
}
Observer1.php | Plus you are able to have as many ConcreteObserver as you want
class Observer1 implements IObserver
{
public function update($subject): void
{
if ($subject->state < 5) {
echo "Observer1: Reacted to the event.\n";
}
}
}
Clinet.php
$subject = new Subject();
$o1 = new Observer1();
$subject->attach($o1);
$subject->someYourLogic();
There is no built-in method, I'm afraid. The shadow copy approach is the best way.
A simpler way, if you have control over the class, is to add a modified variable:
$this->modified = false;
When I modify the object in any way, I simply use
$obj->modified = true;
This way I can later check
if($obj->modified){ // Do Something
to check if it was modified. Just remember to unset($obj->modified) before saving content in a database.
We can implement it without observer.
For pure php, we can use $attributes & $original to check what has been modified check this explanation if needed.
$modifiedValues = [];
foreach($obj->attributes as $column=>$value) {
if(!array_key_exists($column, $obj->original) || $obj->original[$column] != $value) {
$modifiedValues[$column] = $value;
}
}
// then check $modifiedValues if it contains values
For Laravel user, we can use the isDirty() method. Its usage:
$user = App\User::first();
$user->isDirty(); //false
$user->name = "Peter";
$user->isDirty(); //true

Creating graph with php

I wanna create and store graph in php. I have bus schedule, so I decided to create 2 classes:
class Vertex
{
public $city_id;
public $time;
}
class Edge
{
public routeId;
public end_vertex;
}
after this I'm trying to fill my graph. It should be something like hashtable where key will be Vertex object and it'll have many edges.
prototype example:
foreach ($data as $route)
{
$v = new Vertex($route->startCity, $route->startTime)
if(!graph[$v]) {
graph[$v] = [];
}
graph[$v].add(new Edge($route->routeId, new Vertex($route->city_id, $route->startTime + $route->arrivalTime)));
}
but there is one really big problem, as I understand object cannot be used as array key! Maybe I'm in a wrong way? How to create graphs correctly in php? I'm a newbie in this.
In PHP, only simple types can be used as array indices. Complex types, like arrays, objects and resources do not work properly.
Edit: Oh, if memory serves me right, you should watch out for booleans as well, I seem to recollect an issue I had with them.
Edit2: In your case, the object graph should be pointing at the objects, not an array.
So, for example, your code would look like:
$v = new Vertex();
$v->add(new Edge());
$vertices[] = $v;
Edit3: I noticed some serious syntactic flaws in your code. I don't know the exact reason, but if you really can't get them straight, I would advice that you give the PHP manual a couple of looks.
Edit4: By the way, you are using an object as an array index, not a class. There is no PHP data type for classes, there is only class names, which are plain strings.
See my answer here PHP approach to python's magic __getattr__() and combine it with the __toString() method.
BUT I would off-load this kind of stuff to something like gearman, if it's something more complex.
AND there's a library too http://nodebox.net/code/index.php/Graph

Using a Setter with Multidimensional Arrays

I'm trying to create a __set for an object in PHP that works with multidimensional arrays. Is this even possible?
I would like to be able to something like the following: $post->comments[0]['uid']=3;. However, comments is actually going to be a key in a private cache variable $_cache['comments']=array(). It'd be nice if the __set function could somehow get both the base key (comments) and the index (0) as well as the key/value it is setting (uid/3). However, that's not possible.
I've thought about making $_cache['comments'] and array of ArrayObjects but that wouldn't let me define a custom _get/_set overload. Instead, I think that I might end up having to create a new Comments object and then fill the array with those. However, I really wouldn't like to do this and it'd be sweet if somehow PHP could handle nested arrays in __set overloads.
I'm using Mongo and would like if I could just have one single object for each document. However, arrays objects in Mongo are creating a bit of a problem for me. I would like to just handle them as an array in PHP but that doesn't seem possible. The setter needs to take $post->comments[0]['uid']=3 and update both the cache as well as setting $this->data['comments'][0]['uid']=3.
I know that if comments was an array of objects I could do this:
$post->comments[0]->uid=3;
///Sets $_cache['comments'][0]->uid=3;
And it would work because the getter for comments would return the array of objects and allow it to access the uid property. I could then have a getter/setter within the comments object that would somehow edit the $post->data through a pseudo "friend" function/hack. However, I don't see an easy way of accomplishing this with arrays....
Any advice?
That's more complex than you actually imagine. You can accomplish what you want with a heap of workarounds, but it's seldomly worth the effort.
If ->comments itself is resolved by a getter method, than assigning something to the [0] subarray won't actually end up in the private property. And ->comments[0]= will not even invoke your setter method. Instead this is a read access.
To make this work at all you would have to make your __get method return an reference of & $this->_cache['comments'].
If you want to intercept set accesses in that comments array you would indeed need ArrayObject. The difference is that this requires to override offsetGet and offsetSet instead of __get and __set. But again, since you are accessing a further subarray, the __get method will actually be used and you need to return another reference, or yet again a level of ArrayObject workaround goo.
I jumped through some of these hoops when building my own PHP wrapper class.
https://github.com/gatesvp/MongoModel
It's still in the the works, but it does handle some basic "map this object to DB".
There's virtually nothing worthwhile written in PHP chat rooms or the php documentation that's going to be useful to you, Adam. Most of the suggestions tend along the lines of implementing interface ArrayAccess or extending class ArrayObject, both in the SPL. In fact, there is a surprisingly straightforward solution to your problem: $post->comments[0]['uid']=3 using overloaded setter __set().
Define private $comments = array(); in class post. For convenience, use a text key for the first subscript of $comments: here, integer 0 becomes, say, "zero". You then invoke the setter as follows:
$post->zero = ['uid', 3];
This invokes the magic setter because there is no publicly declared property $zero in class post: "The overloading methods are invoked when interacting with properties or methods that have not been declared or are not visible in the current scope." (PHP 5 man page on Overloading.)
The setter can also be setComments(), a convenience because you won't have to discriminate among incoming properties to identify those intended for array comments, but the calling syntax becomes less natural.
Your overloaded, auto-magical function __set receives two arguments: a property and a value:
public function __set($property, $value) {
very reminiscent of Crockford's JSON protocol. It is helpful to think of it in those terms.
Since property "zero" that you sent in does not exist in classpost, it needs to be trapped, and my preferred method, since the first subscript in property comments will likely have several values, is to define a private array of supported subscript values in post:
private $indices = [
"zero" => 0,
"one" => 1,
"two" => 2,
"three" => 3
];
When the index for comments arrives in __set() as $property, it is verified to exist in $indices. Now you simply iterate through the array supplied in $value, extract
uid and its corresponding value, then assign to $comments as follows:
public function __set($property, $value) {
if (array_key_exists($property, $this->indices) && is_array($value))
foreach ($value as $uid => $uid_value)
$this->comments[$this->indices[property]][$uid] = $uid_value;
else
...
}
with $this->indices[property] being used to extract the integer value 0 to be used to
index the first dimension of comments, and $uid_value extracted with value int 3 to be assigned.
The approach outlined here is not a gimmick, workaround or clever trick. It's a straightforward design technique intended to work with one of SPL's facilities and can, in principle, be extended to arrays of arbitrary dimension. I have the design implemented in a production system so, if you're still having difficulty, post here and I'll help you to debug your application. Best of luck!
I believe the closest you can do for overloading some properties is to use the magic method __set() defined here: http://us.php.net/__set
I am not sure you can handle the [0] before it gets taken by the PHP compiler...
So your other solution would be to transform comments into a method
public function comments($id) {
return $this->obj[$id]; // Obj
}
And the object you return has the __set property
class Obj {
private $id;
public function __set($key, $value) {
if($key === 'uid') {
$_cache = $GLOBALS['_cache'];
$_cache['comments'][$this->id]->uid = $value;
}
}
}
There is a lot of code missing here, but you can figure out how to do it with this __set method()
Create a function instead of trying to hack it on top of something that isn't even meant for that.
public function setCommentUid($commentId, $uid) {
$this->_cache['comments'][$commentId]->uid = $uid;
}
//then...
$post->setCommentUid(0, 3);
This makes it much simpler to use the class and it's much easier to see what it does.

Value objects vs associative arrays in PHP

(This question uses PHP as context but isn't restricted to PHP only. e.g. Any language with built in hash is also relevant)
Let's look at this example (PHP):
function makeAFredUsingAssoc()
{
return array(
'id'=>1337,
'height'=>137,
'name'=>"Green Fred");
}
Versus:
class Fred
{
public $id;
public $height;
public $name;
public function __construct($id, $height, $name)
{
$this->id = $id;
$this->height = $height;
$this->name = $name;
}
}
function makeAFredUsingValueObject()
{
return new Fred(1337, 137, "Green Fred");
}
Method #1 is of course terser, however it may easily lead to error such as
$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here
Of course, one might argue that $myFred->naem will equally lead to error, which is true. However having a formal class just feels more rigid to me, but I can't really justify it.
What would be the pros/cons to using each approach and when should people use which approach?
Under the surface, the two approaches are equivalent. However, you get most of the standard OO benefits when using a class: encapsulation, inheritance, etc.
Also, look at the following examples:
$arr['naem'] = 'John';
is perfectly valid and could be a difficult bug to find.
On the other hand,
$class->setNaem('John');
will never work.
A simple class like this one:
class PersonalData {
protected $firstname;
protected $lastname;
// Getters/setters here
}
Has few advantages over an array.
There is no possibility to make some typos. $data['firtsname'] = 'Chris'; will work while $data->setFirtsname('Chris'); will throw en error.
Type hinting: PHP arrays can contain everything (including nothing) while well defined class contains only specified data.
public function doSth(array $personalData) {
$this->doSthElse($personalData['firstname']); // What if "firstname" index doesn't exist?
}
public function doSth(PersonalData $personalData) {
// I am guaranteed that following method exists.
// In worst case it will return NULL or some default value
$this->doSthElse($personalData->getFirstname());
}
We can add some extra code before set/get operations, like validation or logging:
public function setFirstname($firstname) {
if (/* doesn't match "firstname" regular expression */) {
throw new InvalidArgumentException('blah blah blah');
}
if (/* in debbug mode */) {
log('Firstname set to: ' . $firstname);
}
$this->firstname = $firstname;
}
We can use all the benefits of OOP like inheritance, polymorphism, type hinting, encapsulation and so on...
As mentioned before all of our "structs" can inherit from some base class that provides implementation for Countable, Serializable or Iterator interfaces, so our structs could use foreach loops etc.
IDE support.
The only disadvantage seems to be speed. Creation of an array and operating on it is faster. However we all know that in many cases CPU time is much cheaper than programmer time. ;)
After thinking about it for some time, here's my own answer.
The main thing about preferring value objects over arrays is clarity.
Consider this function:
// Yes, you can specify parameter types in PHP
function MagicFunction(Fred $fred)
{
// ...
}
versus
function MagicFunction(array $fred)
{
}
The intent is clearer. The function author can enforce his requirement.
More importantly, as the user, I can easily look up what constitutes a valid Fred. I just need to open Fred.php and discover its internals.
There is a contract between the caller and the callee. Using value objects, this contract can be written as syntax-checked code:
class Fred
{
public $name;
// ...
}
If I used an array, I can only hope my user would read the comments or the documentation:
// IMPORTANT! You need to specify 'name' and 'age'
function MagicFunction(array $fred)
{
}
Depending on the UseCase I might use either or. The advantage of the class is that I can use it like a Type and use Type Hints on methods or any introspection methods. If I just want to pass around some random dataset from a query or something, I'd likely use the array. So I guess as long as Fred has special meaning in my model, I'd use a class.
On a sidenote:
ValueObjects are supposed to be immutable. At least if you are refering to Eric Evan's definition in Domain Driven Design. In Fowler's PoEA, ValueObjects do not necessarily have to be immutable (though it is suggested), but they should not have identity, which is clearly the case with Fred.
Let me pose this question to you:
What's so different about making a typo like $myFred['naem'] and making a typo like $myFred->naem? The same issue still exists in both cases and they both error.
I like to use KISS (keep it simple, stupid) when I program.
If you are simply returning a subset of a query from a method, simply return an array.
If you are storing the data as a public/private/static/protected variable in one of your classes, it would be best to store it as a stdClass.
If you are going to later pass this to another class method, you might prefer the strict typing of the Fred class, i.e. public function acceptsClass(Fred $fredObj)
You could have just as easily created a standard class as opposed to an array if it is to be used as a return value. In this case you could care less about strict typing.
$class = new stdClass();
$class->param = 'value';
$class->param2 = 'value2';
return $class;
A pro for the hash: It is able to handle name-value combinations which are unknown at design time.
When the return value represents an entity in your application, you should use an object, as this is the purpose of OOP. If you just want to return a group of unrelated values then it's not so clear cut. If it's part of a public API, though, then a declared class is still the best way to go.
Honestly, I like them both.
Hash arrays are way faster than making objects, and time is money!
But, JSON doesn't like hash arrays (which seems a bit like OOP OCD).
Maybe for projects with multiple people, a well-defined class would be better.
Hash arrays might take more CPU time and memory (an object has a predefined amount), though its hard to be sure for every scenario.
But what really sucks is thinking about which one to use too much. Like I said, JSON doesn't like hashes. Oops, I used an array. I got to change a few thousand lines of code now.
I don't like it, but it seems that classes are the safer way to go.
The benefit of a proper Value Object is that there's no way to actually make an invalid one and no way to change one that exists (integrity and "immutability"). With only getters and type hinting parameters, there's NO WAY to screw it up in compilable code, which you can obviously easily do with malleable arrays.
Alternatively you could validate in a public constructor and throw an exception, but this provides a gentler factory method.
class Color
{
public static function create($name, $rgb) {
// validate both
if ($bothValid) {
return new self($name, $rgb);
} else {
return false;
}
}
public function getName() { return $this->_name; }
public function getRgb() { return $this->_rgb; }
protected function __construct($name, $rgb)
{
$this->_name = $name;
$this->_rgb = $rgb;
}
protected $_name;
protected $_rgb;
}
I have worked with OOP Languages over 10 years.
If you understand the way objects work you will love it.
Inheritance, Polymorphism, Encapsulation, Overloading are the key advantage of OOP.
On the other hand when we talk about PHP we have to consider that PHP isn't a full featured Object Oriented language.
For example we cant use method overloading or constructor overloading (straightforward).
Associative arrays in PHP is a VERY nice feature but i think that harms php enterprise applications.
When you write code you want to get clean and maintainable application.
Another think that you loose with Associative arrays is that you can't use intellisense.
So i think if you want to write cleanner and more maintainable code you have to use the OOP features when it is provided.
I prefer to have hard-coded properties like in your second example. I feel like it more clearly defines the expected class structure (and all possible properties on the class). As opposed to the first example which boils down to just always remembering to use the same key names. With the second you can always go back and look at the class to get an idea of the properties just by looking at the top of the file.
You'll better know you're doing something wrong with the second one -- if you try to echo $this->doesntExist you'll get an error whereas if you try to echo array['doesntExist'] you won't.

Is referencing and calling methods via strings in PHP a bad idea?

I've always worry about calling methods by referencing them via strings.
Basically in my current scenario, I use static data mapper methods to create and return an array of data model objects (eg. SomeDataMapper::getAll(1234)). Models follow the Active Record design pattern. In some cases, there could be hundreds of records returned, and I don't want to put everything into memory all at once. So, I am using an Iterator to page through the records, as follows
$Iterator = new DataMapperIterator('SomeDataMapper', 'getAll', array(1234));
while ($Iterator->hasNext()) {
$data = $Iterator->next();
}
Is that a good way of doing this? Is it a bad idea to pass as strings the name of the mapper class and the method? I worry that this idea is not portable to other languages. Is this generally true for languages like Ruby and Python? If so, can anyone recommend a good alternative?
FYI, for future peoples' refernce, I call the method like this:
$method = new ReflectionMethod($className, $methodName);
$returnValue = $method->invokeArgs(null, $parameters);
This is essentially a version of the factory pattern - Using strings to create a object instance.
However, I question the design idea of using an iterator to control the paging of data - that's not really the purpose of an iterator. Unless we just have name confusion, but I'd probably prefer to see something like this.
$pager = new DataMapperPager( 'SomeDataMapper', 'someMethod', array(1234) );
$pager->setPageNum( 1 );
$pager->setPageSize( 10 );
$rows = $pager->getResults();
foreach ( $rows as $row )
{
// whatever
}
Of course, DataMapperPager::getResults() could return an iterator or whatever you'd want.
It is an acceptable way of doing it. Both Python and Ruby support it and thus should be portable. Python can do it as easily as PHP can, however Ruby has a little more to it. In Python at least, it is useful for when the particular class you're referencing has not yet been imported nor seen yet in the file (i.e. the class is found lower in the same file as where you're trying to reference it.)
Getting a class object from a string in Ruby: http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
PHP doesn't really support the passing of functions any other way. All dynamic method invocation functions in PHP take what they call a "callback" - see http://us.php.net/manual/en/language.pseudo-types.php#language.types.callback for documentation on that. As you'll see, they're just string or arrays of strings in different usage patterns, so you're not far off.
There are however, design patterns that work around this. For instance, you could define a DataMapper interface that all of your mapper classes must implement. Then, instead of passing in the class and method as string, you could pass the mapper instance to your iterator and since it requires the interface it could call the interface methods directly.
pseudocode:
interface DataMapper
{
public function mapData($data);
}
class DataMapperIterator ...
{
public function __construct(DataMapper $mapper, ...)
{
...
}
...
public function next()
{
... now we can call the method explicitly because of interface ...
$this->mapper->mapData($data);
}
}
class DataMapperImplemenation implements DataMapper
{
...
public function mapData($data)
{
...
}
...
}
Calling methods by name with passed in strings isn't horrible, there's probably only a performance penalty in that the bytecode generated can't be as optimized - there will always be a symbol lookup - but I doubt you'll notice this much.

Categories