When to Use Static VS Instantiated Classes

When to use static vs instantiated classes

This is quite an interesting question -- and answers might get interesting too ^^

The simplest way to consider things might be :

  • use an instanciated class where each object has data on its own (like a user has a name)
  • use a static class when it's just a tool that works on other stuff (like, for instance, a syntax converter for BB code to HTML ; it doesn't have a life on its own)

(Yeah, I admit, really really overly-simplified...)

One thing about static methods/classes is that they don't facilitate unit testing (at least in PHP, but probably in other languages too).

Another thing about static data is that only one instance of it exists in your program : if you set MyClass::$myData to some value somewhere, it'll have this value, and only it, every where -- Speaking about the user, you would be able to have only one user -- which is not that great, is it ?

For a blog system, what could I say ? There's not much I would write as static, actually, I think ; maybe the DB-access class, but probably not, in the end ^^

Performance of using static methods vs instantiating the class containing the methods

From here, a static call is 4 to 5 times faster than constructing an instance every time you call an instance method. However, we're still only talking about tens of nanoseconds per call, so you're unlikely to notice any benefit unless you have really tight loops calling a method millions of times, and you could get the same benefit by constructing a single instance outside that loop and reusing it.

Since you'd have to change every call site to use the newly static method, you're probably better spending your time on gradually refactoring.

when to use static method or simple class method?

You can find the long answer here: How Not To Kill Your Testability Using Statics

The TL;DR version of it is:

  • A static method is nothing more than a namespaced function, Foo::bar() does not significantly differ from foo_bar().
  • Whenever you call a static method, or a function for that matter, you're hardcoding a dependency. The code that reads $bar = Foo::bar(); has a hardcoded dependency to a specific Foo class. It is not possible to change what Foo refers to without changing that part of the source code.
  • An object is a "soft" dependency. $bar = $foo->bar(); is flexible, it allows room to change what $foo refers to. You use this with dependency injection to decouple code from other code:

    function baz(Foo $foo) {
    $bar = $foo->bar();
    ...
    }
  • You can call Foo::bar() anytime from anywhere. If Foo::bar has some dependency it depends on, it becomes hard to guarantee that this dependency is available at the time you're calling the method. Requiring object instantiation requires the object's constructor to run, which can enforce requirements to be set up which the rest of the methods of the object can depend on.

  • Constructors together with dependency injecting objects into other functions are very powerful to

    1. create seams in your codebase to make it possible to "take it apart" and put it together in flexible ways
    2. put checks into strategic places to ensure requirements are met for certain parts of the code (at object instantiation time the constructor enforces a sane state of its little part of the world, its object), which makes it a lot easier to localise and contain failures.

    Think of it like compartmentalising your app and putting firewalls between each compartment with a supervisor in charge of each one; instead of everyone just running around in the same room.

  • Any time you write new Class, you may as well write Class::staticMethod(), the hardcoded dependency is the same.

So the decision comes down to:

  • What are the requirements of this class? Does it need to ensure certain preconditions are met before any of its code can run (e.g. a database connection needs to be available), or are all methods just self-contained little helper methods?
  • How likely are you to maybe want to substitute this class for another class? Does this class produce side effects (e.g. writing to a file, modifying some global state) which may not always be desirable and hence a different version of it may be useful under some circumstances?
  • May you need more than one instance of this class at the same time, or is the nature of the class such that there are no individual instances needed?

Start using unit tests, which require you to take your app apart and test each little part individually to ensure it works, and you'll see where the advantage of object instantiation and dependency injection lie.

Is a class instantiated when a static method is called in a non-static class?

Static methods differ from instance methods in that no instance of the class they belong to needs to have been created for them to be called. When you call a static method, you in fact make the call using the name of the type rather than an instance of the type - which should reinforce the idea that static methods are not called on instances. That bears repeating and emphasis: No instance of a class is required to call a public static method of that class.

Now, your example is malformed, but presumably, the line: if( Foo.SomeCheck() ) is calling the SomeCheck static method using the name of the type: Foo - not an instance. Bar however, has to be instantiated in order to make this call - however, in your example, you don't have a well-formed instance of Bar. Code generally has to exist inside a method (or a member initializer) - which you don't have here.

To respond to the other parts of your question. Assuming the code in question is part of an instance method, something has to instantiate Bar - and invoke that method. That something would have to create or otherwise acquire an instance of Bar. Reference types will always be creted on the heap - but that's largely irrelevant here.

As for garbage collection, you normally shouldn't worry about this. The .NET runtime makes sure to cleanup instances that are not referenced from any root object in your program. Roots are typically instances that reside somewhere on the callstack or are referenced by static members of one type or another. Since we don't see any code here that creates or references Bar it's impossible to say when it will be collected. For instance, if Bar is a singleton and stored somewhere in a static variable, it may live for a very long time - perhaps the entire lifetime of the program. You can't really know without seeing all of the code that manipulates and manages Bar.

Should a class with only static methods be static?

Does it matter?

Making a class static ensures that it can never be instantiated by generating a compiler error should the user attempt to do so. If the class, consisting of only static members, is simply not intended to be instantiated, there is no reason not to make it static. You can choose not to do so, but instances of such a class aren't going to be very useful, and users creating these instances are going to be left quite confused.

On the other hand, if you intend for instances of this class to be created but you expect derived classes to implement their own instance members, chances are that this class should be abstract, rather than static (and perhaps those instance members should be stated upfront via abstract definitions or an interface).

When to use static classes in PHP?

The Static instance of a class only happens once, and its variables are available to any instance of the class. Instances have their own individual values which are not accessible to other instances, except where they are marked static.

Instances are useful when there will be more than one instance of the class.

When using a static method, does the class every get instantiated?

When I call increment using the StaticTest.increment() syntax, does the class ever get instantiated?

The class, itself, is loaded (by the classloader), if it isn't already loaded. If it's already loaded, it is not loaded a second time. No instances of the class (objects of that class's type) are created, because you haven't created any.

Assuming all of the code that calls StaticTest.increment() is using the same classloader (which is normally the case), it doesn't matter how many different bits of code call that static method, just a single copy of the class is used. They all share it. E.g.:

// Some bit of code somewhere
StaticTest.increment();

// Another bit of code somewhere else
StaticTest.increment();

// A third bit of code in yet another place
StaticTest.increment();

Once all of those have run, the no private static member in StaticTest has the value 3.

What if no class of that type exists on the heap already?

Then then classloader loads it.


Contrast that code with this (no statics):

public class NonStaticTest {
private int no = 0;

public void increment()
{
no++;
}

public int getNo() // So we can see the results
{
return no;
}
}

Now, we can't do this:

NonStaticTest.increment(); // WRONG, fails with error saying `increment` is not static

We do this instead:

NonStaticTest instance = new NonStaticTest();
instance.increment();
System.out.println(instance.getNo()); // "1"

The first time code does that, the NonStaticTest class is loaded by the classloader. Then, the new NonStaticTest() expression creates an instance of the class, which has a no member. The second time code does that, NonStaticTest has already been loaded, so it's not loaded again. Then the new NonStaticTest() expression creates a second instance of the class.

If we had three bits of code all doing the above, each of them would see "1", because no is specific to an instance of the class rather than being attached to the class itself.



Related Topics



Leave a reply



Submit