phparchitect-2019-08

(Rick Simeone) #1
http://www.phparch.com \ August 2019 \ 35

Internal Apparatus


Generated Singletons

Edward Barnard


This month we study the Singleton Design Pattern, but with a twist. We start with a correct


implementation but get it wrong by refactoring. We’ll examine the PHP generated code, each
step of the way, to understand what went wrong. We’ll observe at least two reasons the Singleton
Design Pattern is now considered an anti-pattern. We’re preparing to learn useful variations next
month by seeing precisely how it works under the hood.

Preparing to Pivot
It’s time to pivot. With new work assignments come new
directions. Next month begins the new series Pragmatic PHP;
we’ll start with a design pattern that’s now considered an
anti-pattern, the Singleton. We’ll use that knowledge to create
some useful variations.
PHP’s generated-code listings are much like assembly-lan-
guage listings. That makes them fun if, as I am, you’re into
that sort of thing! We’ll practice seeing the structure and
using that knowledge to focus in on the very-few lines of
interest. Make sure you read July 2019’s Internal Apparatus to
understand the generated code.
This month we’ll study the generated code for the Singleton
and some useful variants. We won’t, however, worry about
why they are useful—that comes next month.

The Singleton


The Singleton Design Pattern is a way to guarantee that
one instance, and only one, of a class exists, or can ever exist.
Typically, in a PHP application, you see them used for system
resources like database or cache handlers where you only want
to make one connection to that service. PHP frameworks

sometimes design the framework with Singletons accessible
through some sort of registry.
Listing 1 shows a Singleton implementation. (We’ll be
using names of Minnesota State Parks for our examples.) The
first thing you might notice is our constructor is private, so
users can’t create new instances of our class. They must use
the provided getInstance() method.
We use -d opcache.opt_debug_level=0x10000 to show the
PHP compiler’s generated code:

php -d opcache.opt_debug_level=0x10000 \
GeneratedSingleton/CamdenStatePark.php

Output 1 on the next page shows the generated code for our
Singleton class.

Mainline Code
The first section, lines 1–8, is the generated code for outside
the class declaration. The code generator numbers these
lines L0–L4. The number in parentheses is the PHP file’s line
number. Line L0 corresponds to our PHP file line 2, as shown
by the (2) in parentheses. Line L1 matches PHP file line 4, and
so on. Our PHP file’s line 2 (declare strict types) and line 4
(namespace) become no-operation (NOP) instructions, as does
the class declaration at PHP file line 6.
The first section is labeled the mainline code, as indicated
by the notation $_main: at Output 1, line 1. Each mainline
code section finishes by returning the value 1. We see this at
generated line L4, which corresponds to the last line of our
PHP file.

Constructor
The second section, Output 1 lines 10–15, correspond to
our function __construct(). The section preamble, lines
10-12, tell us:


  • This is the function __construct().

  • The code we’re seeing is before the optimizer step.

  • This section corresponds to Listing 1, lines 10-11.
    We see no reference to the fact that this __construct() is a
    private method. The PHP compiler takes care of that before
    we get to the point of generating code.


Listing 1. Class CamdenStatePark


  1. <?php

  2. declare(strict_types=1);



  3. namespace App\GeneratedSingleton;



  4. class CamdenStatePark {

  5. /* @var CamdenStatePark /

  6. private static $instance;



  7. private function __construct() {

  8. }



  9. public static function getInstance(): self {

  10. if (!self::$instance) {

  11. self::$instance = new self;

  12. }

  13. return self::$instance;

  14. }

  15. }

Free download pdf