That quote is fun – why fun? it makes a lot of statements, but it doesn’t explain the reasoning behind them. I’m hoping that’s an incomplete quote – but given the propensity for “me too” posting on forums and the illiterate whiny “TLDR”/ “AAAH, WALL OF TEXT” that probably is the entire thing. It makes claims, but doesn’t back them up with any examples, similes or other devices to support it. In marketing circles that’s called “authoritative text”.
So let’s actually DISCUSS the topic!
The problem as I see it is too often many programmers seem to want it to be a vs… a question of one or the other instead of the rational choice of AND. Objects AND procedural. You see this in how they write code; you have the die-hards and nubes who refuse to ever touch objects as they’re “too complex” and the zealot-like recently converted who start wrapping EVERYTHING in objects whether it’s warranted or not.
Some tasks are inefficient/wasteful as objects. Objects by their very nature bring large memory overheads, often increasing the number of function calls… this is made worse when the simplest of things are wrapped in functions for no reason as methods. A declared object keeps all it’s variables in memory once they are initialized and/or declared until you release the object or manually release them with unset – this can lead to a very large memory footprint.
On the other hand, objects are like Vegas. What goes on in Object stays in Object. The reduction in the use of global namespace is very attractive, the ability to have public and private values is also very attractive… but more important than all that:
Objects are polymorphic – you can declare them once and have all values the same across ten variables of the same thing automatically; and they expandable, you can add new properties via inheritance.
Procedures on the other hand pass values on the stack and release values when they end – meaning you generally have better garbage collection sticking to them so long as you don’t go nuts using ‘globals for no reason’. Well written procedures passing values by reference and returning the result can be faster, less code,
BUT they lack inheritance – and in PHP they aren’t overloadable (very few languages allow for overloading). Once you make a procedure you cannot ‘enhance it’ without writing a whole new procedure with a whole new name; meaning you have to backtrack to every time it’s called just to change it if desired.
The choice for me comes down to something I read in either a smalltalk or modula book quite a long time ago… a series of short questions to ask yourself:
Is the data being handled “object-like” – as in when you first reference it ALL it’s values are being initialized for use.
Are you going to run more than one instance of the data/handler code simultaneously?
Will one or more classes be inheriting from this object in the future or might the user want to expand it thus?
It shouldn’t be a question of JUST one or JUST the other – they’re just tools in your toolbox and as always, just use the right tool for the right job. Some examples:
PDO – database connections are IDEAL for objects… you can make the initial connection a local object to prevent code appendages from EVER having access, you can pass the object by reference without any of the security information contained within becoming global. You can choose to easily expand the PDO object with new methods and variables and modify the constructor to set up anything you want. Perfect candidate to be an object and vastly superior to the various mysql_ functions.
For example, extending PDO.
class dbPDO extends PDO {
public $tablePrefix;
public function __construct($dbType,$dbName,$server,$port,$username,$password,$tablePrefix) {
$dsn=$dbType.':dbname='.$dbName.';host='.$server.(
empty($port) ? '' : ';port='.$port
);
parent::__construct($dsn,$username,$password);
$this->tablePrefix=$tablePrefix;
}
function tableExists($tableName) {
try {
$qHandle=$this->query(
"SHOW TABLES LIKE '".$this->tablePrefix.$tableName."'"
);
/* damned shame we can't trust rowCount */
$result=$qHandle->fetchAll();
return (count($result)>0);
} catch (PDOException $e) {
echo 'Error - ',$e->getMessage(),'<br />';
return false;
}
}
function countRows($tableName) {
$result=$this->query(
'SELECT COUNT(*) AS COUNT FROM '.$this->tablePrefix.$tableName
);
return $result->fetchColumn();
}
}
But let’s just look at a simple common function… like say we wanted to take any text and turn it into camelbacks:
function camelBack($inString) {
return lcfirst(str_replace(
array(
' ',"\
","\ ","\\r",' '
),'',ucwords($inString)
));
}
Simple short common function – not a candidate for heavy modifications… why would this standalone function EVER need to be an object… or why would you put it into one? It’s USEFUL being global in scope and doesn’t need any extra overhead.
Or this function:
function isValidEmail($address) {
if (filter_var($address,FILTER_VALIDATE_EMAIL)==FALSE) {
return false;
}
/* explode out local and domain */
list($local,$domain)=explode('@',$address);
$localLength=strlen($local);
$domainLength=strlen($domain);
return (
/* check for proper lengths */
($localLength>0 && $localLength<65) &&
($domainLength>3 && $domainLength<256) &&
(
checkdnsrr($domain,'MX') ||
checkdnsrr($domain,'A')
)
);
}
Another example of there being NO reason to put it into an object or make it part of an object. You might want to call it at any point in your code for any variable, so global scope function for the win.
Again, right tool for the right job. Too often I’m seeing people wrapping the simplest of things in objects for no good reason – at the same time I see people being gun-shy of them quite often for tasks they do well…
One thing I’m going to mention is the ancestor of objects, the RECORD – which in pascal is called a record (funny that) and in C is declared as a STRUCT; PHP has similar functionality in it’s “string indexed” arrays which allow any array element to be any data type. (Am I praising something with loose/nonexistant typecasting? I guess I am.) You’ll often hear the claim that procedural involves “passing too many variables” – this claim is typically a bunch of nonsense if you wrap up those variables into complex nested arrays… To that you’ll hear the claim that “it takes too much memory as every variable passed is copied” – true enough, unless you pass that nice big array by REFERENCE. Passing by reference just makes a pointer to the original copy instead of a copy – consuming very little memory and letting in many cases procedural code have all the versatility of objects… since the data is stored in the array, and you can just pass a different array to each function.
I believe it’s important to understand all three approaches and use whichever one seems like the least code and least complex code to do the job. If it feels like you’re code is getting needlessly complex, it probably is.
As the old saying goes, the less code you use the less there is to break.