phparchitect-2019-08

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

Generated Singletons


Internal Apparatus


We just made a mistake. Singletons are tricky, and we have
just discovered one reason the Singleton is generally consid-
ered an anti-pattern. Let’s use a unit test to show the problem.
See Listing 6.


Lines 23 and 24 verify the problem. We intended to have
separate Singletons for CamdenStatePark and CarleyStatePark.
In fact, they are both the same object, and of class Camden-
StatePark. The method CarleyStatePark::getInstance()
produced the same Camden object, not a Carley object. We
did this to ourselves when we removed the code duplication.
Ouch!


Under the Hood


What’s happening under the hood? We’ll be examining the
generated code to take a look. But, that means wading through
many lines of low-level code. We’ve already seen most of this
code as the original CamdenStatePark class of Listing 1.


That familiarity is an advantage. It’s one of the tricks I use
for quickly understanding long listings of generated code.
Since we already know what most of this code looks like, we
can now focus on the structure. We can see what we need
in a moment or two even though it looks like we’re wading
through all that code. Like most skills,
this one becomes easier with practice.


We’ll first check the generated
code for the parent class StatePark.
We’ll note any differences from our
first generated code, Output 1. We’ll
then do the same for the modified
CamdenStatePark. Finally, we’ll compare
the CamdenStatePark code to the
CarleyStatePark generated code. See
Output 2 for the StatePark code. The
listings are large, but we’ll scream
through this examination remarkably
quickly.


How do we take in a generated-code
listing like this? We can quickly see
it’s structured into sections. Since this
is a class file with no extraneous code
outside the class declaration, the main-
line code section, the first section, can
be ignored. It’s a series of no-ops and
that same RETURN 1 we’ve seen before.


We can quickly recognize the second
section as an empty method with no
PHP return statement. As compared
to the original CamdenStatePark listing,
there’s nothing new here either. The
third section is also identical to what
we saw earlier.


Does this even make sense? Yes, it
does. We moved code to a parent
class. We designated the parent class as


Listing 6. Singleton Unit Tests


  1. <?php

  2. declare(strict_types=1);



  3. namespace App\Test\TestCase\GeneratedSingleton;



  4. use App\GeneratedSingleton\CamdenStatePark;

  5. use App\GeneratedSingleton\CarleyStatePark;

  6. use App\GeneratedSingleton\StatePark;

  7. use PHPUnit\Framework\TestCase;



  8. class StateParkTest extends TestCase {

  9. public function testCamden(): void {

  10. $camden = CamdenStatePark::getInstance();

  11. static::assertInstanceOf(StatePark::class, $camden);

  12. static::assertInstanceOf(CamdenStatePark::class, $camden);

  13. static::assertNotInstanceOf(CarleyStatePark::class, $camden);

  14. }



  15. public function testCarley() {

  16. $carley = CarleyStatePark::getInstance();

  17. static::assertInstanceOf(StatePark::class, $carley);

  18. // Oops - this shows the problem

  19. static::assertInstanceOf(CamdenStatePark::class, $carley);

  20. static::assertNotInstanceOf(CarleyStatePark::class, $carley);

  21. }

  22. }


Output 2. Class StatePark generated code


  1. $_main: ; (lines=5, args=0, vars=0, tmps=1)

  2. ; (before optimizer)

  3. ; /PragmaticPHP/pragma/src/GeneratedSingleton/StatePark.php:1-21

  4. L0 (2): NOP

  5. L1 (4): NOP

  6. L2 (6): EXT_STMT

  7. L3 (6): NOP

  8. L4 (21): RETURN int(1)



  9. App\GeneratedSingleton\StatePark::__construct: ; (lines=3, args=0, vars=0, tmps=0)

  10. ; (before optimizer)

  11. ; /PragmaticPHP/pragma/src/GeneratedSingleton/StatePark.php:10-11

  12. L0 (10): EXT_NOP

  13. L1 (11): EXT_STMT

  14. L2 (11): RETURN null



  15. App\GeneratedSingleton\StatePark::getInstance: ; (lines=19, args=0, vars=0, tmps=7)

  16. ; (before optimizer)

  17. ; /PragmaticPHP/pragma/src/GeneratedSingleton/StatePark.php:13-18

  18. L0 (13): EXT_NOP

  19. L1 (14): EXT_STMT

  20. L2 (14): V0 = FETCH_STATIC_PROP_R string("instance") (self) (exception)

  21. L3 (14): T1 = BOOL_NOT V0

  22. L4 (14): JMPZ T1 L12

  23. L5 (15): EXT_STMT

  24. L6 (15): V3 = NEW 0 (static) (exception)

  25. L7 (15): EXT_FCALL_BEGIN

  26. L8 (15): DO_FCALL

  27. L9 (15): EXT_FCALL_END

  28. L10 (15): V2 = FETCH_STATIC_PROP_W string("instance") (self) (exception)

  29. L11 (15): ASSIGN V2 V3

  30. L12 (17): EXT_STMT

  31. L13 (17): V6 = FETCH_STATIC_PROP_R string("instance") (self) (exception)

  32. L14 (17): VERIFY_RETURN_TYPE V6

  33. L15 (17): RETURN V6

  34. L16 (18): EXT_STMT

  35. L17 (18): VERIFY_RETURN_TYPE

  36. L18 (18): RETURN null

  37. LIVE RANGES:

  38. 3: L10 - L11 (tmp/var)

  39. 6: L14 - L15 (tmp/var)

Free download pdf