3

I'm trying to learn when static functions should be used, and have had a difficult time finding an answer my questions. I am creating a class User, which is related to a class Group. If I have a user id and I want to get a user object from that, is it better to do something like

$existingUser = User::get($userId); 

where the class is defined like this

class User()
{ 
    public static function get($id){
        $user = new User();
        return $user->findById($id);
    }
    public function findById($id) {
        //find and populate user object
    }
}

or

$existingUser=new User();
$existingUser->findById($userId);

where the class is defined like this

class User()
{ 
    public function findById($id) {
        //find and populate user object
    }
}

What about if I were to write a function which returns an array of Group objects based on a user id?

class User()
{ 
    //stuff
    $groupArray = Group::getAllByUserId($this->getId())
    //stuff
}

or

class User()
{ 
    //stuff
    $group = new Group();
    $groupArray = $group->findAllByUserId($this->getId());
    //stuff
}

The second method creates an empty group object which is never used. Does it matter? Am I misunderstanding the concept of static? I know it is useful for not having to instantiate a class, so if the function instantiates one anyway, does that kind of defeat the purpose? If so, what would be an example of when a static function would be used?

Anything else I should be considering in this over simplified example?

Reese
  • 1,746
  • 1
  • 17
  • 40
  • possible duplicate of [When do I use static variables/functions in php?](http://stackoverflow.com/questions/1257371/when-do-i-use-static-variables-functions-in-php) – sberry Sep 16 '11 at 22:36

4 Answers4

0

You don't need a static function int he case you show above.

Static functions are really just global functions with a namespace.

Use them when the global state of the application needs to be controlled, or if multiple copies of the function lead to inonsistant results.

Callbacks sometimes need to be static, especially if they are passed as a string.

Byron Whitlock
  • 52,691
  • 28
  • 123
  • 168
  • "Callbacks sometimes need to be static, especially if they are passed as a string." - no, you can use `array($object, $method)`. – OZ_ Sep 16 '11 at 22:53
-2

You should probably check out this question on Active Record vs data mapper:

https://stackoverflow.com/questions/2169832/data-mapper-vs-active-record

One take from this question is that static methods on the class for loading/saving aren't really the core functionality of the class in most cases. Further, storing and loading is a kind of abstract concept that is separate from your class objects in most cases.

Isa "user" a data storage and retrieval object? In most cases, no, it is a person represented in your system that has various properties and functions. When you start tying the persistence of that object into the object, you break encapsulation and make it harder to maintain the code. What if next week you want to load your users out of memcache? It's hardly relevant to if a user can have some property or functionality.

Community
  • 1
  • 1
Zak
  • 24,947
  • 11
  • 38
  • 68
  • I think I am using a data mapper (not shown in this example), but I don't understand how that relates – Reese Sep 16 '11 at 22:45
  • Data Mapper implies you have a second outside class with static functions i.e. UserMapper that contains your static methods to find and load users. The analogy sometimes used is, if you were building a car, you wouldn't put an engine factory in the car to get an engine.. You would go to an outside engine factory and request a new engine. – Zak Sep 16 '11 at 22:48
  • *"Data Mapper implies you have a second outside class with static functions"* - it's just wrong realization. – OZ_ Sep 16 '11 at 22:55
  • http://martinfowler.com/eaaCatalog/dataMapper.html -- they don't have to be static, my mistype.. I often see them as static implementations, but I also see a lot of instantiated mapper classes – Zak Sep 16 '11 at 23:00
-2

I find a good rule of thumb is thinking "If I don't have a [class-name], would I expect to be able to call [method-name]?"

If I don't have a user, would I expect to be able to call findByID? Probably not. This is one of the exceptions I come across; a "load" or a "save" method sometimes makes sense to be static.

A perfect example of when to use non-static methods is (most methods in) a Database class - you should always have a database object before you try to run a query on it.

An example of when to use a static method would be a "helper" class, essentially a collection of handy functions. Say you have some methods that help you output HTML, you might have HTML::image(), HTML::url() and HTML::script(). On these, you shouldn't need a HTML object to create an image, URL, and so on.

As for stopping multiple copies of objects being created (one argument for using static methods), you should use a Singleton pattern instead (Google it) to ensure only one copy of the object ever exists.

Joe
  • 15,669
  • 4
  • 48
  • 83
  • Function like `HTML::image()`, `HTML::url()` and `HTML::script()` are one of best examples when you should not use static methods. There is no point in this. YOu would be much better off if you careated a namespace and called `\HTML\img()` or `\HTML\script()`. And any "framework" which used such class should be avoided like black plague. – tereško Sep 16 '11 at 23:21
  • @tereško: You do not always have the luxury to deploy on >=PHP5.3 servers. – phant0m Sep 16 '11 at 23:30
  • @phant0m then call them `html_img()` .. what's the difference ? Just don't pretend that you are "doing OOP" when you are writing a procedural code. – tereško Sep 16 '11 at 23:38
  • @tereško: could you plz explain why functions like HTML::image(), HTML::url()... are one of best examples when you should not use static methods??? What about Filter::isEmail($email) then? Why creating namespaces, arent' static methods more user friendly?! – Marco Demaio Jan 17 '12 at 18:39
  • @MarcoDemaio , can you answer , what is the responsibility of `Filter` class objects ? Your example is breaking SRP , thus it is not an example of *object oriented programming*. If you want to write procedural code then write it. Do not pretend that it is OOP. – tereško Jan 22 '12 at 19:17
  • @tereško: don't know, I suppose it's responsible to work. :-) `(sacrificing user friendy code in favour of full OO design) === 'nonsense';` IMHO `HTML::image(), HTML::url()` are better than `html_img(), html_url()` for 2 reasons: 1) readability, code is tidy inside one single class, 2) if these methods need to share a variable now or in future, such variable can be simply added to the class as `static` too. Anyway I understood what you are saying. – Marco Demaio Jan 23 '12 at 11:11
  • @MarcoDemaio , you might notices from your example the nature of `static` variables as you **are** using the class in this case as pseudo-namespace , and using global state within it. `Trying to mask procedural code as OOP === 'nonsense'`. If you start by recognizing that such utility methods are procedural in nature to begin with, you end up writing much cleaned code , then if you try to wrap them in meaningless OOP concepts "just because". – tereško Jan 27 '12 at 00:21
-2

I'm trying to learn when static functions should be used

Oh, it's so simple: never.

To understand it, read:
http://www.objectmentor.com/resources/articles/ocp.pdf
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/

OZ_
  • 12,492
  • 7
  • 50
  • 68
  • -1 never is over-simplistic. Sure its better to handle a db via dependency injection, but tons of libraries frameworks etc use static methods. In the real world you don't get to build all the code from scratch unfortunately. – Byron Whitlock Sep 17 '11 at 20:25
  • @Byron Whitlock we are talking about writing our own code, not about refactoring 3-d party libraries. And "tons of frameworks use static" isn't argument. It's much more easily to write bad code and don't read books, than read books and write good code. – OZ_ Sep 18 '11 at 07:16
  • 1
    thanks, this has introduced me to a whole new concept (test driven development). i'm now using unit tests for all my code, and avoiding static methods wherever possible. – Reese Sep 20 '11 at 22:23