2011 Answer
This is actually a good question, and I've seen some good answers here. I actually really had to think about this for a bit.
I'd like to add something that I haven't seen in any of the other answers here, even if I don't get any votes, so that future readers can benefit.
Let's take your examples. (I've edited them so that they are functionally identical - they are slightly changed from what you had above.)
The class version:
<?php class Image { private $resource; function resize($width, $height) { $resized = imagecreatetruecolor($width, $height); imagecopyresampled($resized, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource)); $this->resource = $resized; } } $image = new Image(); $image->resource = "./someimage.jpg"; $image->resize(320, 240);
And the function version: <?php
function resize($width, $height, $resource) { $resized = imagecreatetruecolor($width, $height); imagecopyresampled($resized, $resource, 0, 0, 0, 0, $width, $height, imagesx($resource), imagesy($resource)); $resource = $resized; return $resource; } resize(320, 240, "./someimage.jpg");
In practice, these are functionally identical. The main difference is simply the OOP paradigm vs. the procedural paradigm; in OOP, you define a function within a class (this is called a method) that acts upon a member variable, whereas in a procedural program you pass that variable to a function defined in the global scope.
So then, what's the benefit of wrapping a function in a class instead of making it global, since the function still does the same thing?
The main reason you'd want to do this in PHP (and many other languages that I can think of) is scope. @Headspin mentioned this briefly. Defining a resize function in the global scope is all well and good...until you need another function with the same name. What happens?
Generally, you run into one of these solutions:
- (The good.) Your language supports function overloading, so you don't worry about it as long as your arguments are different.
- (The bad.) Your language doesn't support function overloading (or your arguments have to be identical) and so you resort to detailed naming (like
resize_image, resize_container), etc. - (Still bad.) You begin to use namespaces to separate your global functions.
- (The ugly.) Your function accepts anything as an argument and becomes a hot, bloated mess of if/then statements or switch/case blocks for each variable type that it will handle.
My main reason to encapsulate a function in PHP would be to avoid naming conflicts, making the code more intuitive and easier to understand. I could have a resize method in my Image class, and have one in my Container class, and maybe another one in a test class or something, and none of them would conflict with each other. Reading the code, I know that Image->resize() calls the method within the Image class and nothing else.
Not having name conflicts opens up some more possibilities, such as iterating over a group of objects that share a common method name. (This is where interfaces come into play; read about them.) There's a lot of cool stuff you can do.
I guess that's it - I hope that helps. Below is the TL;DR version.
Encapsulating a single function in a class prevents naming conflicts for similar functions, without resorting to namespaces, function overloading, or function renaming. As such, if you have one function that performs a generic task, it may be best to create a class for each variable type that the function handles and convert the function to a class method.
2020 Edit:
I wrote this nine years ago when I was much more into OOP paradigms. The answer isn't necessarily wrong, but I've come to realize that the "stick everything in a class" methodology is a side effect of classic object-oriented, class-based programming that can't support other models. I don't really mess with PHP anymore, so I'm going to write this from a generic programming standpoint.
For current readers - organize your functions. Use file strategies, modules, namespaces - whatever it takes. This is good practice. However, functions don't have to be class methods, and in this day and age I would actually argue that they shouldn't be; functions should be just functions, taking input and creating output with minimal side effects. Modern languages and paradigms have a lot of benefits - one main benefit is that "classes" are no longer necessarily conflated with "namespaces/modules", so you don't need to encapsulate a function in a class (with all the overhead and annoyances that come with that) just for organizational purposes. Benefits of using standalone functions include:
- Standalone functions often can be used in multiparadigm ways - they can be used like class methods (since methods are just functions with a specific parameter binding), or they can be used in a functional way.
- They can more easily be treated as first-class objects and avoid being pinned to a particular implementation.
- They can use generics when possible to avoid repetition when a concept is generic and interfaces are well-defined.
- They can be easily used with interfaces and contracts, depending on the language.
- They are easier to test in isolation without mocks (which is a pitfall of OOP) and they are self-scoping (they don't have to be, but it's not bad practice to avoid side effects outside of the function unless absolutely necessary).
So basically, in 2020, I would not follow my earlier advice:
~~Encapsulating a single function in a class prevents naming conflicts for similar functions, without resorting to namespaces, function overloading, or function renaming. As such, if you have one function that performs a generic task, it may be best to create a class for each variable type that the function handles and convert the function to a class method.~~
Use modern tools and paradigms when possible. Prefer simple functions. If your languages offers alternatives for code organization to classes, use those and only use classes and methods for their true design purpose.
$resourcecome from, genesis? It's passed toimagecopyresampled,imagesx, andimagesybefore it's ever defined.$resourceis still not defined in functionresizebefore it's passed to other functions.