When To Use Static Classes And Methods

Devin Dixon
Jan 4 · 7 min read

Have you ever read something about programming that was outdated or misunderstood and cringed? Many PHP developers can probably relate when they hear misinformation such as “Python has better package management”, “PHP is a slow scripting language”, “The language is not object-oriented”, fractal bad design, etc etc. What is worse is that many of these misconceptions rank first on Google. The use of static has the same problem.

This is part 2 of an article about the use of static class and methods in PHP. The first section of the article that debunked erroneous misconceptions about static was published here:

Debunking The Myths Of Static Methods and Variables

To recap some of the articles points, using static you can:

  1. Have inheritance and public/protected/private accessors function the same.
  2. Can use create polymorphism with Interfaces and Abstract classes
  3. Static Methods are testable.
  4. Have inversion of control with dependency injection.
  5. Unknown side effects are from the programmer, not for a method being static. OOP can have side effects as wells.

Now we can dive into the benefits of static classes, methods and variable, and when to use them.

Benefit: Increased Speed

When an object is instantiated with the new keyword, there is actually a performance cost associated with that action. Code that is not instantiated as an object with the new keyword actually runs about 10%-20% faster.

As an example, let's say we are copying a file from one location to another on our server. We can write a multi-step function like so:

<?php
$file= '/path/to/file.txt';
$desination = '/new/path/to/file.txt';
$result = false;if(file_exist($file)) {
$result =copy($file, $destination);
unlink($file);
}
return $result;

Now we can encapsulate the above code in either an instance or a static method. The function will look like so:

//Interchangable with instance vs static
function($current_file, $new_file) {
$result = false;
if(file_exist($current_file)) {
$result = copy($current_file, $new_file);
unlink($current_file);
}
return $result;
}

The above code does not have a state or potential for side effects. If the file is copied is returns true if is everything fine, otherwise false. Now let’s see say we have 100,000 files to copy.

<?php
$file= '/path/to/file.txt';
$desination = '/new/path/to/file.txt';
for($i=0; $i<1000000; $i++) {
//Instance Version
$filemanger = new FileManager();
$file->copy($file, $destination);
//Static Version
FileManager::copy($file, $destination);
}

For a test you can run on your local, you may use the following gist:

The results were:

Instance Time: 2.1042990684509

Static Time: 1.8717567920685

Two benefits have occurred:

  1. You can speed up our code by not using new, which over 100000 files can be a significant improvement.
  2. Our code is shorter

Now yes we can make improvements like instantiating the FileManager outside the loop in this scenario which will result in only one instantiation being executed, but the point of the test is to prove the new keyword takes more time to execute.

The takeaway is if your object does not need to be instantiated, then static can be faster.

Benefit: Improved Memory Utilization

There will be instances in our applications that we want to utilize shared variables across many scopes instead of each instance having its own copy of the variables.

While there are obvious examples of this use case such as a Registry in an MVC or a User’s Session data (will discuss later) that should be constant across the runtime of an application, another good real-life example is writing an importer.

The US Patent Office has there data available for download, and when you unzip their XML files it's over 350GB worth of information. Parsing through their data, you will notice it has a lot of repeat values in the XML because it's not normalized.

Patents have attribute data, such as each patent belonging to a class type, utility type, status etc. If we have multiple importers running checking against the attributes, its a memory advantage to keep that data static. Example:

//Static Repo
class DataTypes {
//Lets say this array is full of data
public static $utiltiyType = array();
//Lets say this array is also full of data
public static $classTypes = array();
public static function hasUtility($key) {
return isset(self::$utiltiyType[$key]);
}
public static function hasClass($key) {
return isset(self::$classTypes[$key]);
}
}//The Code In Exection
$streamer=XmlStringStreamer::createParser('file.xml');
while ($node = $streamer -> getNode()) {
check1($node);
check2($node);
}
function check1($node) {
if(DataTypes::hasUtility($node->utility)) {
//Do Something
}
}
function check2($node) {
if(DataTypes::hasClass($node->class)) {
//Do Something
}
}

In this example, the use of static when used across multiple functions of different scopes is able to better utilize memory by referencing the data at the same point in memory and not a copy. Its akin to referencing a pointer. In the right scenario, static can have memory improvements.

Use Case: Building Microservices

Many of the programming concepts come from the era of large monolithic applications. Inversion of Control techniques such as Dependency Injection was needed because in a large application a small change can have cascading side effects across the entire system. Its why monolithic code bases are so hard to iterate through.

Microservices do not have the same problems or constraints. Here is an example of a simple Socket Server that receives input from a client and sends an email:

The static part is here:

//Decrypt our encrypted message
Security::init();
$message = Security::decrypt($message);

If the developer wants to change that code with something else, they can easily do so without system-wide effects. The microservice is only 60 lines of code and is its own isolated system. We don’t have monolithic problems.

That is one of the key points of microservices, an architecture that is easy to modify without affecting other parts of the system. There is no need to have massive layers of abstractions or over-architecting the perfect design. If the developer does not like something, they change it. If a developer finds themselves spending an obscene amount of time planning and building the application layer of a microservice, it might be too large to be considered a microservice.

Adding the benefits of increased speed and ability to share memory, static can work nicely in microservices with minimal negative impact.

Use Case: Encapsulating Similar Functions For Organization

Functional programming is a great way to improve your code, and we talk about the benefit of using functional programming in microservices here. But there may come a point in your code when you wish to organize those functions in a more intuitive way.

For example, let's say we write a bunch of math functions:

function add($value1, $value2) {
return $value1+$value2;
}
function subtract($value1, $value2) {
return $value1-$value2;
}
function multiply($value1, $value2) {
return $value1*$value2;
}

That are called like so:

$value = add(5,2);

These are pure functions that do not have a state or cause any side effects. But remembering where they are and how they are called can be a little be difficult. You can encapsulate them as static functions inside a class like so:

class Math {  public static function add($value1, $value2) {
return $value1+$value2;
}
public static function subtract($value1, $value2) {
return $value1-$value2;
}
public static function multiply($value1, $value2) {
return $value1*$value2;
}
}

And you would call them as:

$value = Math::add(5, 2);

This approach still follows the same principles of functional programming, we have just made a slightly more intuitive and organized way of accessing those functions.

Use Case: Enforcing Global Standards Across An Application

In some applications, we want to enforce global standards in an organized and encapsulated way. A great example is a User Session in an application.

When a user is logged in and visits a page in your application, their information will be referenced in several locations. Let’s say we are loading a dashboard for Joe Smith. A flow of processes might look like this:

  • Load Joe’s Messages
  • Load Joe’s Preferences
  • Find Joe’s Recent Posts
  • Get Joe’s Profile Image

A representation of in code can look like this:

<?php
class Session {
private static $_name = 'Joe Smith'; private static $_id = 293840213; public static function getID() {
return self::$_id;
}
public static function getName() {
return self::$_name;
}
}//Pretend this is Laravals Facade for Models
//Will return iterabe objects
$posts = Posts::find(array('user_id' => Session::getID()));
$messages = Messagesa::find(array('user_id' => Session::getID()));'
//etc
//etc

Because the session data is static and also non-mutable, this approach enforces:

  • Consistency across the application, it will always be Joe
  • Security from accidentally or maliciously having the data of the current user be changed
  • Per our points above, improves memory by referencing the same data and speed without using the new operator

Static Is Not A Magic Bullet

To wrap-up, while static does have use cases in which it can excel over using instances, it's not a magic bullet for everything and there are use cases when static should not be used. Some of the use cases are:

  1. In large monolithic applications in higher level implementations. Being used in low-level implementations where there is no abstraction is debatable.
  2. In instances where isolated states are required. Because static is persistent, it can exist in states where you do not want it too.
  3. Holding obscene amounts of data. Static if you are not careful can have issues with the Garbage Collector, and data can end up persisting even when longer being used by your application

Bottom line, learn when and how to use static. It exists for a reason and is not all bad, just developers that misuse it.

Helium MVC

The blog of the Helium MVC and ProdigyView Toolkit

Devin Dixon

Written by

Entrepreneur, Technologist, Runner.

Helium MVC

The blog of the Helium MVC and ProdigyView Toolkit

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade