Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use static vs instantiated classes

Tags:

oop

php

class

PHP is my first programming language. I can't quite wrap my head around when to use static classes vs instantiated objects.

I realize that you can duplicate and clone objects. However in all of my time using php any object or function always ended up as a single return (array, string, int) value or void.

I understand concepts in books like a video game character class. duplicate car object and make the new one red, that all makes sense, but what doesn't is its application in php and web apps.

A simple example. A blog. What objects of a blog would be best implemented as static or instantiated objects? The DB class? Why not just instantiate the db object in the global scope? Why not make every object static instead? What about performance?

Is it all just style? Is there a proper way to do this stuff?

like image 397
user73119 Avatar asked Jul 26 '09 21:07

user73119


People also ask

When Should static classes be used?

A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields. For example, in the . NET Class Library, the static System.

When would you use a static method over an instance method?

Instance method can access the instance methods and instance variables directly. Instance method can access static variables and static methods directly. Static methods can access the static variables and static methods directly. Static methods can't access instance methods and instance variables directly.

When should we use static class in Java?

In Java, the static keyword is primarily used for memory management. We can use the static keyword with variables, methods, blocks, and classes. Using the static class is a way of grouping classes together. It is also used to access the primitive member of the enclosing class through the object reference.

Why You Should Avoid static classes?

Static classes have several limitations compared to non-static ones: A static class cannot be inherited from another class. A static class cannot be a base class for another static or non-static class. Static classes do not support virtual methods.


2 Answers

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 ^^

like image 179
Pascal MARTIN Avatar answered Sep 29 '22 11:09

Pascal MARTIN


The main two reasons against using static methods are:

  • code using static methods is hard to test
  • code using static methods is hard to extend

Having a static method call inside some other method is actually worse than importing a global variable. In PHP, classes are global symbols, so every time you call a static method you rely on a global symbol (the class name). This is a case when global is evil. I had problems with this kind of approach with some component of Zend Framework. There are classes which use static method calls (factories) in order to build objects. It was impossible for me to supply another factory to that instance in order to get a customized object returned. The solution to this problem is to only use instances and instace methods and enforce singletons and the like in the beginning of the program.

Miško Hevery, who works as an Agile Coach at Google, has an interesting theory, or rather advise, that we should separate the object creation time from the time we use the object. So the life cycle of a program is split in two. The first part (the main() method let's say), which takes care of all the object wiring in your application and the part that does the actual work.

So instead of having:

class HttpClient
{
    public function request()
    {
        return HttpResponse::build();
    }
}

We should rather do:

class HttpClient
{
    private $httpResponseFactory;

    public function __construct($httpResponseFactory)
    {
        $this->httpResponseFactory = $httpResponseFactory;
    }

    public function request()
    {
        return $this->httpResponseFactory->build();
    }
}

And then, in the index/main page, we'd do (this is the object wiring step, or the time to create the graph of instances to be used by the program):

$httpResponseFactory = new HttpResponseFactory;
$httpClient          = new HttpClient($httpResponseFactory);
$httpResponse        = $httpClient->request();

The main idea is to decouple the dependencies out of your classes. This way the code is much more extensible and, the most important part for me, testable. Why is it more important to be testable? Because I don't always write library code, so extensibility is not that important, but testability is important when I do refactoring. Anyways, testable code usually yields extensible code, so it's not really an either-or situation.

Miško Hevery also makes a clear distinction between singletons and Singletons (with or without a capital S). The difference is very simple. Singletons with a lower case "s" are enforced by the wiring in the index/main. You instantiate an object of a class which does not implement the Singleton pattern and take care that you only pass that instance to any other instance which needs it. On the other hand, Singleton, with a capital "S" is an implementation of the classical (anti-)pattern. Basically a global in disguise which does not have much use in the PHP world. I haven't seen one up to this point. If you want a single DB connection to be used by all your classes is better to do it like this:

$db = new DbConnection;

$users    = new UserCollection($db);
$posts    = new PostCollection($db);
$comments = new CommentsCollection($db);

By doing the above it's clear that we have a singleton and we also have a nice way to inject a mock or a stub in our tests. It's surprisingly how unit tests lead to a better design. But it makes lots of sense when you think that tests force you to think about the way you'd use that code.

/**
 * An example of a test using PHPUnit. The point is to see how easy it is to
 * pass the UserCollection constructor an alternative implementation of
 * DbCollection.
 */
class UserCollection extends PHPUnit_Framework_TestCase
{
    public function testGetAllComments()
    {
        $mockedMethods = array('query');
        $dbMock = $this->getMock('DbConnection', $mockedMethods);
        $dbMock->expects($this->any())
               ->method('query')
               ->will($this->returnValue(array('John', 'George')));

        $userCollection = new UserCollection($dbMock);
        $allUsers       = $userCollection->getAll();

        $this->assertEquals(array('John', 'George'), $allUsers);
    }
}

The only situation where I'd use (and I've used them to mimic the JavaScript prototype object in PHP 5.3) static members is when I know that the respective field will have the same value cross-instance. At that point you can use a static property and maybe a pair of static getter/setter methods. Anyway, don't forget to add possibility for overriding the static member with an instance member. For example Zend Framework was using a static property in order to specify the name of the DB adapter class used in instances of Zend_Db_Table. It's been awhile since I've used them so it may no longer be relevant, but that's how I remember it.

Static methods that don't deal with static properties should be functions. PHP has functions and we should use them.

like image 34
Ionuț G. Stan Avatar answered Sep 29 '22 12:09

Ionuț G. Stan