Unless you count QBASIC back when I was a kid, I learned to program in the object oriented paradigm a half-decade ago in university, so I understand how it works. I have difficulty, however, implementing it in my large, database-driven PHP applications, because everything is re-initialized on each page load. The only true persistence is the database, but pulling all the data from the database and reconstructing all the objects on every page load sounds like a lot of overhead for not much benefit, as I'll just have to do it all over again on next page load.
Additionally, I run into these sorts of problems when I try to re-factor an application (third attempt now) to OO:
A class called "Person" exists, and it contains a variety of properties. One of the extensions of that class, "Player", contains a "parent" property, of the type "Player". Initially, none of the players start with any parents, so they would all be initialized with that field as NULL. Over time, however, parents would be added to the Players properties, and would reference other Player objects that already exist.
In PHP, however, it's inevitable that I would have to rebuild the class structure with Players already having parents. In such a case, if I instantiate a Player who has as a parent a Player that hasn't been instantiated yet - I have a problem.
Is it necessary to reduce the scope of OO programming when dealing with PHP?
Items not being created by means of parents is indeed something that is tricky. You could do something like, ID referencing and build a PlayerManager
that does the linking for you. By means of RUID
's (Runtime Unique ID's). But of course, you would like to have the parents be created first.
So when creating something like an OO structure of your database, which I would encourage if you want to do some extra manipulations on it besides printing. It is doable to create a player from your DB and then, if it has a parent, create the parent as you would do normally. When arriving at the parent in your while-loop. You can just say, no it is already created. Use a Player-manager class for this, which holds your Players. So it can check if Players (and thus parents) are already there.
So you get a bit of a different way of walking through your DB, instead of just doing it linear.
As for: is it necessary to do so. I actually don't know that much about it myself. It seems, as far as I've seen on the web, that PHP classes are mostly used to created one object that can do smart things (like a DOMDocument
).
But do you really have to convert your DB table to objects? It depends on your type of application. If printing is what you want, it doesn't seem logical. If some big manipulation with a lot of calls to the objects (or normally to the table), I maybe would like to see a nice OO programmed structure.
You're confusing OOP concepts, with concepts about HTTP and persistence.
Your question isn't really about OOP at all- it's about persisting OOP data across multiple HTTP requests.
PHP doesn't automatically persist objects across HTTP requests- it's left up to you to take care of that (in your case, doing just as you said: "pulling all the data from the database and reconstructing all the objects on every page load").
Is it necessary to reduce the scope of OO programming when dealing with PHP?
No. You just need to use lazy loading to instantiate parent player only if it becomes necessary.
Class Player {
protected $id;
protected $name;
protected $parentId;
protected $parent;
public static function getById($id) {
// fetch row from db where primary key = $id
// instantiate Player populated with data returned from db
}
public function getParentPlayer() {
if ($this->parentId) {
$this->parent or $this->parent = Player::getById($this->parentId);
return $this->parent;
}
return new Player(); // or null if you will
}
}
This way if you intantiate player id 40:
$john = Player::getById(40);
It does not have the $parent property populated. Only upon call to getParentPlayer() it is being loaded and stored under that property.
$joe = $john->getParentPlayer();
That is of course only if $parentId is pointing to non-NULL.
Update: to solve problem of duplicate instances stored in protected property when two or more players share single parent, static cache can be used:
protected static $cache = array();
public static function getById($id) {
if (array_key_exists($id, self::$cache)) {
return self::$cache[$id];
}
// fetch row from db where primary key = $id
// instantiate Player populated with data returned from db
self::$cache[$id] = ... // newly created instance
// return instance
}
If you expect to access significant number of parents on every request, it may be feasible to select all records from database at once and store them in another static pool.
OOP programming in PHP is for me more a way of having a good maintainability and a good architecture (composition, factories, component based programing, etc ).
For sure you'll need to rethink some Design Patterns used in persitent envirronments. Pools of objects, etc. And of course some Design Patterns as still completly good in PHP used in short-term module in apache: Singleton, Factory, Adapter, Interfaces, Lazy loading etc.
About the persitence problem there're several solutions. Of course database storage. But you have as well the session storage and application caches (like memcached or apc). You can store serialized objects in such caches. You'll just need a good autoloader to get the classes loaded (and a good opcode to avoid re-interpreting the sources at every requests).
Some objects are really heavy to load and build, we can think for example of an ACL object, loading roles, ressources, default policy, exception rules, maybe even compling some of theses rules. Once you've got it it would be a desaster to rebuild this object at every request. You should really study the way to store/load this finished object somewhere to limit his load time (avoiding SQL requests and build time). Once built it's certainly an object that could have a long life, like 1hour.
The only objects that you cannot store as serialized strings are in fact the one which depends shortly of data updates by concurrent requests. Some websites does not even need to really care about it, accuracy of data is not the same in a public website publishing news and in a financial accouting app. If your application can handle pre-build serialized objects you can see the serialize-storage-load-unserialize as a simple overhead in the framework :-) But effectivly, share nothing, no object listening to all concurrent requests, no write operation on an object shared with a parallel request until this object (or related data) is stored somewhere (and read). Take it as a challenge!