When (if at all) to use static methods [new thread split off from frameworks]

The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

If a method doesn't involve properties or methods in that class, what the heck is the method doing in that class? Move it to the caller.

If it's duplicated in several client classes then you probably have a design problem. If it's so generic it still appears in several classes, and there is too much code to simply duplicate it (more than a one liner), you'll still probably want to have an instance. That way you can test the client code more easily

Honestly, I agree entirely. Those functions don't belong there - in fact their only reasoning is the naming.

But my point is that if you are going to have a function which doesn't involve the object, why instantiate the object in the first place?

The ultimate solution would be to move them to the global namespace. But my point is, its better (IMO) to have a method static within a class than having to instantiate an object where it isn't needed.

As for frameworks, personally I find nothing beats writing your own.

Jake Arkinstall
"Sometimes you don't need to reinvent the wheel;
Sometimes its enough to make that wheel more rounded"-Molona

Yes, and that's exactly what a static member is -- Bound to a global scope. While it is a solution, it's only ultimate in the sense that it's the worst possible solution; The global scope is by definition the most general scope there is, so consequently it's also the most meaningless (As in - devoid of meaning). In effect, any other solution is more precise. Since one of the most fundamental goals of application design (And really, in any kind of communication) is to strike the proper balance between being specific and being abstract, using the global scope is a fail, in the same way that using no abstraction at all is it (But at the other end of the scale).

Shouldn't we open a new topic to get this settled?
I think that we already have got flame threads about this here, but I agree that we are out of topic here.

good old lack of understanding why using the global scope is bad
Native PHP functions are global. Constant are global. UDF are global. Why not classes? I am fine with global space, used to choose different hammer for each type of task. There is no wrong hammer.
By the way, there MUST be some global context, mustn't it? How could you use some factory for generating objects, if this factory is not globally visible? Even Zend has

Suppose you'd want to test this with a unit test, and you realize that Bar::someDestructiveMethod() performs some destructive logic that you don't want to run every time you want to run your test. You would either have to add a conditional inside that method, or you could solve it by removing the static call:

The code becomes more flexible when you can change which objects you want to pass in during runtime. With static calls, you can't do that. You could always add logic to the static methods so you get increased flexibility, but then those methods would get bloated really quickly. But then you lose the power of polymorphism, and you would still be stuck with the hard coded class, whereas passing in an instance instead allows you to pass in whatever class you want, as long as it implements the correct interface.

It becomes more flexible because you designed it to be more flexible, NOT because you simply removed static. The logic you provided to explain your example is a fallacy.

Which still has the exact same limitation. This limitation is caused by a design flaw and has nothing to do with declaring static.

In the second example where you pass in an object, that also has nothing to do with declaring static. That code will work exactly the same whether or not someDestructiveMethod() is declared static, except when you remove static you're limiting the scope for which the method can be applied.

Declaring static does not mean you should use it in a static context all of the time, I thought I made that clear in my last post.

A method I've been trying out lately to allow fluid relationships between objects is, rather than pass an object it's containing object, or pass the object to its container to be stored in an array, the object is given an ID of its container (in this case its container's container, a MapperCollection).

This MapperCollection allows the CommentMapper, PageMapper, ArticleMapper and TopicMapper to be accessed with a simple call.

So, when an article is instantiated it saves the ID of this mapper collection and a method is defined for getting it's mappercollection. Each Mappercollection is stored in a static array to be retrieved by an ID (i.e. a static registry).

So, the article gets its mappercollection by:

PHP Code:

MapperCollection::get($this->id);

Are you seriously suggesting that the mappercollections be stored in an instantiated object's array rather than stay static?

There can be a time when you want multiple databases, which is what my system seemlessly allows for... how much further do we need to go with this?

Oh, and there are great results from my method. Using two versions, exactly the same other than the relationships are solid - there is a 86&#37; speed increase.

Jake Arkinstall
"Sometimes you don't need to reinvent the wheel;
Sometimes its enough to make that wheel more rounded"-Molona

In the second example where you pass in an object, that also has nothing to do with declaring static. That code will work exactly the same whether or not someDestructiveMethod() is declared static, except when you remove static you're limiting the scope for which the method can be applied.

I don't really understand this. Could you give an example.

@Mastodont, you know, not everyone knows how to extend
Zend_Controller_Front, and this is due to the protected constructor (which
as far as I know was private in the beginning), the static method
getInstance() and Late Static Binding. Honestly, it makes no sense to impose
such restrictions on the creation of Zend_Controller_Front, my guess is that
it is a Singleton mainly because a few years ago, when the PHP community
found about design patterns, Singleton was by far the easiest to grasp. Even
today, every developer starting to learn about patterns will spread all over
his code lots of singletons (been there, done that).

The main reason I avoid static function calls is because of late static binding.
(IMHO) The only reasonable use for static methods and properties is when
you want some state to be shared by all instances and you really know it's
gonna be multiple instances. Nevertheless, this can be avoided too in order
to facilitate testing. One example inside ZF using a static method which I
found it to be useful is Zend_Db_Table_Abstract::setDefaultAdapter(). And
supposing you have a peculiar table which needs some other adapter, you
have the possibilities to do just that.

On the same note, I really don't like Zend_Controller_Action_HelperBroker

A static member is pretty much as the prototype inside JS. I said "pretty
much" because we don't yet have all the means to achieve this. The idea is
that we may have state (properties) shared by all the instances of the class.
If you find yourself using a static method just because your framework is
"fully OOP" then there's something wrong in there.

// This still works, since $foo is an instance of Foo! Except since it's
// declared statically you're not forced to create an instance of Foo if all you
// need to do is call staticMethod().
$foo = new Foo();
$foo->staticMethod();

// This is bad! I think PHP may "let" you attempt to call the function this way
// because of legacy reasons, but should never, ever do this. If method uses
// $this at all then calling it like this will fail. If it needs $this then it
// also shouldn't be static and should never be called like this anyway. If it
// does not need $this, then it SHOULD be declared static as usage like this is
// possible and is a much clearer definition.
Foo::method();

PHP has global scope, but it doesn't have namespaces. In PHP singletons help from trashing your global namespace.

Namespaces are overrated. What is the functional difference between, say, Namespace::function() and namespace_function()? I know that, with namespaces, you can declare the namespace you use and then call methods without declaring their namespace each time, but personally I'd always rather have the namespace explicit on each call.

Also, OOP is all about behavior, which is implemented through instance method calls. As Marcus has said above, if method is generic enough that it doesn't use any of an instance's state, it really don't belong to that object. The point of OOP are objects -- as opposed to classes -- and their interaction; a few weeks working with Javascript will teach you that.

Namespaces are overrated... a few weeks working with Javascript will teach you that.

On any large project, namespaces or at least pseudo-namespace functionality is pretty much required. Have you ever worked on a large project? Or perhaps a project in another language such as C++?

What is the functional difference between, say, Namespace::function() and namespace_function()?

PHP doesn't implement true namespaces anyway (yet). It does have autoclass loading and a very common design technique is one class per file. Do you suggest one function per file? Do you know how much of a mess it would be to include a file for every function used? Not to mention you'd either be passing a rediculous number of variables by reference or using the global keyword and getting your geek card taken away.

Suppose you'd want to test this with a unit test, and you realize that Bar::someDestructiveMethod() performs some destructive logic that you don't want to run every time you want to run your test. You would either have to add a conditional inside that method, or you could solve it by removing the static call:

Not sure how that's the ultimate solution. Instead of finding a truly meaningful place for something, your goal is to dump it off in some global god area for later confusion.

Originally Posted by arkinstall

As for frameworks, personally I find nothing beats writing your own.

Except for the fact that you have to maintain it going forward. Nothing beats writing it at the time, but I would rather not write an MVC Framework or an IoC container when someone has already created one that suits my needs.

True, however as we all know, Frameworks are built to work with a large variety of applications - which means there can be alot of stuff you just don't need in there.

Well, don't use it. They're not forcing you to use it. Castle Windsor is a beast of an IoC container. I don't use all of its features, but that's not going to stop me from using it. If something was overly complicated and/or had a lot of friction to it, I would then look at other options.

Originally Posted by arkinstall

Yes, but the question is - where is that?

That depends on what it's doing. Since I don't know the role "Hello World" is actually playing in the system, then I really can't tell you. Do you have a real life example of something?

I think we're all caught up in these very random, obtuse examples. Instead of trying to prove something based on code that's not real, we should post real examples of problems and try to figure out how we would improve them.

In general you should prefer nonstatic methods to static methods. When in doubt, make the function nonstatic. If you really want a function to be static, make sure that there is no chance that you'll want it to behave polymorphically.

A workaround or alternative in some cases might be to have an instantiated object hiding behind a static method. That would make it possible to keep the option of configuring behavior by replacing the object.