Statics and Class Properties
Tags: php, laravel, zval, singletonpattern
Published: 2019-03-22 15:28:11

---
title: Statics and Class Properties
published: true
tags: php,laravel,zval,singleton-pattern
canonical_url: https://smcrow.net/2017/10/18/statics-and-class-properties/
---

In a previous post, I talked about singleton services that were retrieved from the container and how they could impact queue workers. At the end of the post I added a small comment on statics and how they could also cause trouble. I’d like to go into some more details on class properties.

## Two Types of Class Properties

Maybe class property isn’t the correct wording here, but that’s what I’m going to refer to them as. In PHP we have _instance_ properties which are tied to an **instance** of an object, and we have _static_ properties which are tied to a **class**.

### Instance Properties

These are properties that require an instance to reference. Memory is allocated for each instance, and for each property on that instance.

```php
class Example {
    public $propertyOne = 'one';
}

$example = new Example;
echo $example->propertyOne; // 'one'
```

### Static Properties

These are properties that are tied to the class. They don’t require an instance of the class. Only a **single** memory location is allocated for the reference. You could think of these as global variables as you can pretty much reference them from anywhere.

```php
class Example {
    public static $propertyOne = 'one';
}

echo Example::$propertyOne; // 'one'
```

## The `zval`

PHP uses `zval` to store objects and references in memory. If you have the [xdebug](https://xdebug.org/) tool installed you can use the `xdebug_debug_zval` method to gather some information about specific objects.

Here’s a new version of the example class:

```php
class Example {
    public $propertyOne;
    public static $propertyTwo;
    
    public function __construct($propertyOne)
    {
        $this->propertyOne = $propertyOne;
    }
}
```

If we use it in the following way:

```php
$example1 = new Example('foo');
$example2 = new Example('bar');

print xdebug_debug_zval('example1');
print xdebug_debug_zval('example2');
```

The following results are printed out:

```php
example1: (refcount=1, is_ref=0)=class Example { 
    public $propertyOne = (refcount=0, is_ref=0)='foo' 
}

example2: (refcount=1, is_ref=0)=class Example { 
    public $propertyOne = (refcount=0, is_ref=0)='bar' 
}
```

The **refcount** refers to the number of times a variable is referenced. Notice that both `$example1` and `$example2` are only referenced once.

However, if I were to modify the code a bit:

```php
$example1 = new Example('foo');
$example2 = new Example('bar');
$example3 = $example1;
```

You can see that the refcount increases on `$example1`.

```php
example1: (refcount=2, is_ref=0)=class Example { 
    public $propertyOne = (refcount=0, is_ref=0)='foo' 
}

example2: (refcount=1, is_ref=0)=class Example { 
    public $propertyOne = (refcount=0, is_ref=0)='bar' 
}
```

PHP actually uses this value to determine which references should be cleaned up during [garbage collection](http://php.net/manual/en/features.gc.php)

Something else to note, is that the `static` property `$propertyTwo` is not shown in the output of `xdebug_debug_zval`. This is because it is not tied to the instance, and should not be accessible from the instance.

## PHP Variable Life Cycle

You can read more about the [garbage collection](http://php.net/manual/en/features.gc.php) process to get an idea of how instance variables are cleaned up during garbage collection. Something to note is that _statics are not garbage collected_. Static variables are cleared after the script is done executing. That’s why, from the [Queues and Stateful Services](https://dev.to/nexmo/queues-and-stateful-services-1gi8-temp-slug-1378948) article, statics can have an impact on the queue workers. The script never stops executing.

However, for normal use, each request will have its own isolated static variables. This is _not_ like Java, where the statics will stick around until the application or the server is restarted.

## Static Uses

The static life cycle is especially useful if there is information that needs to be passed around to multiple classes for the duration of the request. Optimal memory usage can be achieved by use of the _singleton pattern_ or by _lazy loading and locking_ statics.

### Lazy Loading and Locking

I’m not sure what the official term for this is. It’s a combination of lazy loading, and locking a property-value.

```php
class MemberList {
    private static $names = [];
    
    public static function getNames()
    {    	
    	return (empty(self::$names))
    	    ? self::$names = app(NameRetriever::class)->getNames();
    	    : self::$names;
    }
}
```

In this example I am retrieving a list of names from the `NameRetriever` which has been injected from the application container. However, I am only going to do this the first time it’s requested.

Any subsequent requests to the `MemberList::getNames()` method will return the cached values inside of `$names`. This can be especially useful if the operation for retrieving the list of names is overly complex.

Laravel actually uses a similar technique for serving singletons. They are stored in an array and their existence is checked before instantiation whenever an object is requested from the application container.

### Singleton Pattern

Singletons are classes that are only instantiated once. Any subsequent request for the class will return the same instance. Laravel provides this functionality via `app->singleton()`. However, this pattern can be applied even if you aren’t using a framework.

```php
class ExampleSingleton {
    private static $instance = null;

    public static function create()
    {
        return (is_null(self::$instance))
        ? self::$instance = new self()
        : self::$instance;
    }
    
    private function __construct() {
        // constructor intentionally left private
    }
}
$singletonOne = ExampleSingleton::create();
$singletonTwo = ExampleSingleton::create();

if ($singletonOne === $singletonTwo) {
    echo "They are equal!";
} else {
    echo "They are not!";
}
```

Running this script returns that _they are equal_.

This is very similar to the _lazy loading and locking_ method. Only this time we are locking the `$instance` so that it stores one instance of the class, and then returning it each time. We are also making the `__construct` method `private` to prevent bypassing the singleton pattern.