7

I'm writing a bunch of generic-but-related functions to be used by different objects. I want to group the functions, but am not sure if I should put them in a class or simply a flat library file.

Treating them like a class doesn't seem right, as there is no one kind of object that will use them and such a class containing all these functions may not necessarily have any properties.

Treating them as a flat library file seems too simple, for lack of a better word.

What is the best practice for this?

Chris Baker
  • 49,926
  • 12
  • 96
  • 115
Old McStopher
  • 6,295
  • 10
  • 60
  • 89
  • 5
    Don't misuse OOP (classes) for function collections. – Felix Kling May 12 '11 at 18:20
  • 1
    @all: Please pay attention not in the way how to do something, but in the main question -- is it honest OOP, or we have a problem somewhere here. – gaRex May 12 '11 at 21:19

8 Answers8

6

Check out namespaces:

http://www.php.net/manual/en/language.namespaces.rationale.php

Wrapping them in a useless class is a workaround implementation of the concept of a namespace. This concept allows you to avoid collisions with other functions in large projects or plugin/module type deployments.

EDIT

Stuck with PHP 5.2?

There's nothing wrong with using a separate file(s) to organize utility functions. Just be sure to document them with comments so you don't end up with bunchafunctions.php, a 20,000 file of procedural code of dubious purpose.

There's also nothing wrong with prefixes. Using prefixes is another way to organize like-purpose functions, but be sure to avoid these "pseudo-namespaces" already reserved by the language. Specifically, "__" is reserved as a prefix by PHP [reference]. To be extra careful, you can also wrap your function declarations in function_exists checks, if you're concerned about conflicting functions from other libraries:

if (!function_exists('myFunction')) {
    function myFunction() {
            //code
    }
}

You can also re-consider your object structure, maybe these utility functions would be more appropriate as methods in a base class that all the other objects can extend. Take a look at inheritance: http://www.php.net/manual/en/language.oop5.inheritance.php. The base class pattern is a common and very useful one:

abstract class baseObject {
    protected function doSomething () {
        print 'foo bar';
    }
    public function getSomething () {
        return 'bar foo';
    }
}

class foo extends baseObject {
    public function bar () {
        $this->doSomething();
    }
}

$myObject = new foo();
$myObject->bar();
echo $myObject->getSomething();

You can experiment with the above code here: http://codepad.org/neRtgkcQ

Chris Baker
  • 49,926
  • 12
  • 96
  • 115
2

I'd use classes with static methods in such case:

class Tools {

    static public function myMethod() {
         return 1*1;
    }

}

echo Tools::myMethod();

EDIT

As already mentioned by Chris and yes123: if the hoster already runs PHP 5.3+, you should consider using namespace. I'd recommend a read of Matthew Weier O'Phinney's article Why PHP Namespaces Matter, if you're not sure if it's worth switching to namespaces.

EDIT

Even though the ones generalizing usage of static methods as "bad practice" or "nonsense" did not explain why they consider it to be as such - which imo would've been more constructive - they still made me rethinking and rereading.

The typical arguments will be, that static methods can create dependencies and because of that can make unit testing and class renaming impossible.

If unit testing isn't used at all (maybe programming for home/personal use, or low-budget projects, where no one is willing to pay the extra costs of unit testing implementations) this argument becomes obsolete, of course.

Even if unit testing is used, creation of static methods dependencies can be avoided by using $var::myMethod(). So you still could use mocks and rename the class...

Nevertheless I came to the conclusion that my answer is way too generalized.

I think I better should've wrote: It depends.

As this most likely would result in an open ended debate of pros and cons of all the different solutions technically possible, and of dozens of possible scenarios and environments, I'm not willing going into this.

I upvoted Chris' answer now. It already covers most technical possibilities and should serve you well.

Jürgen Thelen
  • 12,745
  • 7
  • 52
  • 71
  • this is a bad behaviour. If you need this just use namespace -1 – dynamic May 12 '11 at 18:33
  • 5
    @yes123 Remember lots and lots of servers and hosting platforms out there don't yet run PHP 5.3. Namespaces (along with lots of other useful 5.3 features) may not be an option. – Michael Berkowski May 12 '11 at 18:46
  • If you use bad code because your hosting company can't keep up with a simple php update you should change your hosting company. At least never suggest bad pratice only for that – dynamic May 12 '11 at 18:53
  • 3
    @Yes - While I agree with you on principle (see my answer here), in practice this is not practical. Some hosts use binding multi-year contracts, if you've paid for 4 years of hosting and cannot terminate, changing hosts is not practical. You're right that one should always strive to write the best code *possible*, but that HAS to take in to account environment. If you don't have the latest version of PHP, it isn't possible to use namespaces. At the end of the day, there is no "wrong" code, only code that works or does not work. – Chris Baker May 12 '11 at 18:58
  • @yes123: I agree that I should've mentioned namespaces for 5.3+. But to generalize that you should switch your hoster, only because the hoster hasn't the most current PHP version running, is just plain unrealistic. At least in business. I of course recommend to update to the most stable too, but there are many other reasons to stick to an older PHP version. Whatever the reasons are (from Apache/PHP modules incompatible with 5.3, not upgradable, additional license costs, etc.): they do exist and are perfectly reasonable from the customers point of view and should be honored. – Jürgen Thelen May 12 '11 at 19:12
  • 1
    @jurgen: The fact you can't use PHP 5.3 isn't a good reason to suggest a bad pratice. If you can't use namespace the only thing you can do is to declare your function name with the same prefix like `function array*(){}` – dynamic May 12 '11 at 20:06
  • So, because the webhost is on 5.2 and I'm unable to change hosting packages right now, what's the general consensus? Just put functions in a utilities.php file and give them all the same function name prefix? – Old McStopher May 12 '11 at 23:17
  • Aside from the debate about changing hosts because they aren't up-to-date with their server, a static class for utility functions is nonsense. – Chris Baker May 13 '11 at 14:44
2

I would usually stick them in a class anyway and mark the methods static. You might call it a static class, even though PHP actually has no such thing (you can't put the static keyword in front of a class). It's still better than having the functions globally because you avoid possible naming conflicts. The class becomes a sort of namespace, but PHP also has its own namespace which may be better suited to your purpose.

You might even find later that there are indeed properties you can add, even if they too are static, such as lazy-loaded helper objects, cached information, etc.

Tesserex
  • 17,166
  • 5
  • 66
  • 106
  • @teresko My comment about disliking PHP's namespaces was personal opinion, but I guess I can remove it. Aside from that my advice isn't unique here. I've seen too many function collections (namespace or not) that end up promoting tons of global variables instead. – Tesserex May 12 '11 at 18:30
1

Treating them as a class does give you the benefit of a namespace, though you could achieve the same thing by prefixing them like PHP does with the array_* functions. Since you don't have any properties, that basically implies that all your methods are static (as Class::method()). This isn't an uncommon practice in Java.

By using a class, you also have the ability, if necessary, to inherit from a parent class or interface. An example of this might be class constants defined for error codes your functions might return.

EDIT: If PHP 5.3+ is available, the Namespace feature is ideal. However, PHP versions still lag in a lot of hosts and servers, especially those running enterprise-stable Linux distributions.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
0

I've seen it a few different ways, all have their warts but all worked for the particular project in which they were utilized.

  1. one file with all of the functions
  2. one file with each function as its own class
  3. one massive utilities class with all of the methods
  4. one utils.php file that includes files in utils folder with each function in its own file
Don
  • 542
  • 3
  • 6
0

Yes, it's OK formally... As any class is methods + properties. But when you pack in class just some functions -- it`s become not ideal OOP. If you have bunch of functions, that groupped, but not used some class variables -- it' seems, that you have somewhere a design problem.

My current feeling here is "Huston, we have a problem".

gaRex
  • 4,144
  • 25
  • 37
0

If you use exactly functions, there one reason to wrap them in static class - autoloader.
Of course, it creates high coupling, and it's may to be bad for testing (not always), but... Simple functions are not better than static class in this case :) Same high coupling, etc.
In ideal OOP architecture, all functions will be methods of some objects. It's just utopia, but we should to build architecture as close as we can to ideal.

OZ_
  • 12,492
  • 7
  • 50
  • 68
-1

Writing a bunch of "generic-but-related" functions is usually bad idea. Most likely you don't see problem clear enough to create proper objects.

It is bad idea not because it is "not ideal OOP". It is not OOP at all.

"The base class pattern" brought by Chris is another bad idea - google for: "favor composition over inheritance".

"beeing extra careful" with function_exists('myFunction') is not but idea. It is a nightmare. This kind of code is currently avoided even in modern javascript...

smentek
  • 2,820
  • 1
  • 28
  • 32
  • None of my suggestions are inherently "bad ideas" (they produce working code), but regurgitating GoF is (it produces no code), especially without any practical examples to back up the generalizations. *Favor* is the key word at play in your quote; composition *usually* makes more sense than inheritance, so that's why one should favor it - we aren't using it just because it's cooler or someone said so. In this instance, with the details provided, inheritance makes sense and passes Ockham's Razor in being the simplest to implement AND the simplest to explain. Thanks for the input, though. – Chris Baker May 16 '11 at 16:12
  • Sorry, I thought you are about to produce "good" code, if "working" is enough for you... then you are right. – smentek May 17 '11 at 11:26
  • And don't get me wrong I'm not against inheritance in every case but what you described: "maybe these utility functions would be more appropriate as methods in a base class that all the other objects can extend." Is just wrong. Inhereintance is good when A IS B. "Bunch of generic functions" is neither A or B. Unnecessary coupling! – smentek May 17 '11 at 11:41