SlideShare a Scribd company logo
PHP7 Anonymous Classes:
Behind the Mask
PHP7 Anonymous Classes
• What is an Anonymous Class?
• A class that is defined “inline”, within user code, at runtime
• Sometimes called “inline” or “nested” classes
• Don’t have the scope of the class where they are created
• Not assigned a class name
PHP7 Anonymous Classes
• What is an Anonymous Class?
• How do I use an Anonymous Class?
PHP7 Anonymous Classes
• How do I use an Anonymous Class?
• No name given to the class (internally assigned by PHP)
• Closing semi-colon (;)
• Constructor arguments passed in class definition
• All objects created by the same anonymous class declaration are instances of
that class (the internal class reference is identical).
$objectInstance = new class( 'arguments'... ) {
// defined properties and methods
};
PHP7 Anonymous Classes
function locationFormatBuilder (array $location = []) {
return new class (...$location) {
const POINT_MASK = '% 3d° % 2d' %5.2f" %s';
public function __construct($latitude, $longitude) {
$this->latitude = $latitude;
$this->longitude = $longitude;
}
protected function point($point, $orientation) {
…
return vsprintf(self::POINT_MASK, [$degrees, $minutes, $seconds, $direction]);
}
public function __toString() {
return vsprintf(
'%s, %s',
[$this->point($this->latitude, ['N','S']), $this->point($this->longitude, ['E','W'])]
);
}
};
}
PHP7 Anonymous Classes
$locations = [
[ 51.5074, -0.1278 ], // London
[ 40.7128, -74.0059 ], // New York
[ -22.9068, -43.1729 ], // Rio de Janeiro
[ -33.9249, 18.4241 ], // Cape Town
[ 19.0760, 72.8777 ], // Mumbai
[ 35.6895, 139.6917 ], // Tokyo
[ -33.8688, 151.2093 ], // Sydney
[ 31.7683, 35.2137 ], // Jerusalem
];
foreach ($locations as $location) {
echo locationFormatBuilder($location), PHP_EOL;
}
51° 30' 26.00" N, 0° 7' 40.00" W
40° 42' 46.00" N, 74° 0' 21.00" W
22° 54' 24.00" S, 43° 10' 22.00" W
33° 55' 29.00" S, 18° 25' 26.00" E
19° 4' 33.00" N, 72° 52' 39.00" E
35° 41' 22.00" N, 139° 41' 30.00" E
33° 52' 7.00" S, 151° 12' 33.00" E
31° 46' 5.00" N, 35° 12' 49.00" E
PHP7 Anonymous Classes
PHP7 Anonymous Classes
• How do I use an Anonymous Class?
• Can “implement” and “extend”
• Can use Traits
$objectInstance = new class( 'arguments'... ) {
// defined properties and methods
};
PHP7 Anonymous Classes
• Anonymous Class Factories
• Builds an Anonymous Class that extends the “userModel” class with optional
Traits
• Uses “eval()”
$anonymousModel = (new AnonymousClassFactory('userModel'))
->withConstructorArguments($databaseConnection)
->withTraits('softDelete', 'auditable')
->create();
PHP7 Anonymous Classes
trait softDelete {
protected $softDelete = true;
}
trait auditable {
protected $auditable = true;
}
class userModel {
protected $dbConnection;
protected $loggingEnabled;
public function __construct($dbConnection, $loggingEnabled = false) {
$this->dbConnection = $dbConnection;
$this->loggingEnabled = $loggingEnabled;
}
}
PHP7 Anonymous Classes
$dbConnection = new PDO('sqlite:example.db');
$loggingEnabled = true;
$className = 'userModel';
$traits = implode(', ', ['softDelete', 'auditable']);
$classDefinition = <<<ANONYMOUS
new class($dbConnection, $loggingEnabled) extends {$className} {
use {$traits};
};
ANONYMOUS;
$anonymousUserModelClassInstance = eval("return $classDefinition;");
PHP7 Anonymous Classes
object(class@anonymous)#2 (4) {
["dbConnection":protected]=>
object(PDO)#1 (0) {
}
["loggingEnabled":protected]=>
bool(true)
["softDelete":protected]=>
bool(true)
["auditable":protected]=>
bool(true)
}
PHP7 Anonymous Classes
• Anonymous Class Factories
• In Search of an Anonymous Class Factory
https://markbakeruk.net/2016/05/03/in-search-of-an-anonymous-class-factory/
• Anonymous Class Factory – The Results are in
https://markbakeruk.net/2016/05/12/anonymous-class-factory-the-results-are-in/
$anonymousModel = (new AnonymousClassFactory('modelClass'))
->withConstructorArguments($databaseConnection)
->withTraits('softDelete', 'auditable')
->create();
PHP7 Anonymous Classes
class userController {
protected $user;
public function __construct(userModel $user) {
$this->user = $user;
}
}
$controller = new UserController($anonymousUserModelClassInstance);
PHP7 Anonymous Classes
• What is an Anonymous Class?
• How do I use an Anonymous Class?
• What Limitations are there to Anonymous Classes?
PHP7 Anonymous Classes
• What Limitations are there to Anonymous Classes?
• Definition and Instantiation in a Single Step
• Cannot be Serialized
• Effectively Final
• No OpCaching
• No Documentation (DocBlocks)
• No IDE Hinting
PHP7 Anonymous Classes
• What is an Anonymous Class?
• How do I use an Anonymous Class?
• What Limitations are there to Anonymous Classes?
• Why would I use Anonymous Classes?
PHP7 Anonymous Classes
• Why would I use Anonymous Classes?
• One-off Objects
• Private Classes
• Test Mocking
• On-demand Typed Structures (instead of generic arrays or StdClass)
• Ad-hoc adapters in a loosely coupled architecture
• To bypass Autoloading
PHP7 Anonymous Classes
• Why would I use Anonymous Classes?
• Test Mocking
• https://mfyu.co.uk/post/anonymous-classes-in-php-7-are-fantastic-for-tests
PHP7 Anonymous Classes
• Inner- or Nested-Classes
class SpyMaster {
private $targetObject;
protected $objectMission;
public function __construct($targetObject) {
$this->targetObject = $targetObject;
$this->objectMission = new SpyObjectMission($targetObject);
}
protected function getHandler() {
…
}
public function infiltrate() {
return $this->getHandler();
}
}
PHP7 Anonymous Classes
• Inner- or Nested-Classes
class SpyObjectMission {
public $methods = [];
public $invoker;
public function __construct($targetObject) {
$reflector = new ReflectionObject($targetObject);
$this->invoker = $this->getInvoker($reflector, $targetObject);
}
protected function getInvoker(ReflectionObject $reflector, $targetObject) {
$staticMethods = array_column($reflector->getMethods(ReflectionMethod::IS_STATIC), 'name’);
$this->methods = array_diff(
array_column($reflector->getMethods(), 'name’), $staticMethods)
);
$invoker = function($methodName, ...$args) {
return self::$methodName(...$args);
};
return $invoker->bindTo($targetObject, get_class($targetObject));
}
}
PHP7 Anonymous Classes
• Inner- or Nested-Classes
protected function getHandler() {
return new class ($this->objectMission, $this->staticMission) {
private $objectMission;
public function __construct(SpyObjectMission $objectMission) {
$this->objectMission = $objectMission;
}
public function __call($methodName, $args) {
if (in_array($methodName, $this->objectMission->methods)) {
$invoker = $this->objectMission->invoker;
return $invoker($methodName, ...$args);
}
throw new Exception("Object Method {$methodName} does not exist");
}
};
}
PHP7 Anonymous Classes
• Inner- or Nested-Classes
$test = new classThatWeWantToTest(1, 2, 3);
$spy = (new SpyMaster($test))
->infiltrate();
echo 'SPY FOR TEST #1', PHP_EOL;
echo $spy->privateMethodThatWeWantToTest(), PHP_EOL;
PHP7 Anonymous Classes
• Inner- or Nested-Classes
• Closures, Anonymous Classes and an alternative approach to Test Mocking
(Part 2)
• https://markbakeruk.net/2017/07/30/closures-anonymous-classes-and-an-alternative-
approach-to-test-mocking-part-2/
• Closures, Anonymous Classes and an alternative approach to Test Mocking
(Part 4)
• https://markbakeruk.net/2018/01/23/closures-anonymous-classes-and-an-alternative-
approach-to-test-mocking-part-4/
PHP7 Anonymous Classes
Phpanpy
Mock object framework for unit testing
Like Mockery https://packagist.org/packages/mockery/mockery
PHP7 Anonymous Classes
$dummyConstructorArguments = [1,2];
$points = (new PhpanpyAnonymousDoubleFactory('GeodeticLatLong', ...$dummyConstructorArguments))
->setMethodReturnValuesList([
'getLatitude' => [51.5074, 40.7128, -22.9068, -33.9249, 19.0760, 35.6895, -33.8688, 31.7683],
'getLongitude' => [-0.1278, -74.0059, -43.1729, 18.4241, 72.8777, 139.6917, 151.2093, 35.2137],
])->setMethodReturnValuesFixed([
'getElevation' => 0.0
])->create();
$line = (new PhpanpyAnonymousDoubleFactory('GeodeticLine’))
->suppressOriginalConstructor()
->setMethodReturnValuesFixed([
'getNextPoint' => $points
])->create();
PHP7 Anonymous Classes
try {
for($i = 0; $i < 10; ++$i) {
$point = $line->getNextPoint();
echo sprintf(
"%+ 9.4f %+ 9.4f % 7.4f",
$point->getLatitude(), $point->getLongitude(), $point->getElevation()
), PHP_EOL;
}
} catch (Exception $e) {
echo $e->getMessage();
}
PHP7 Anonymous Classes
new class(...$this->constructorArgs) extends GeodeticLatLong {
use PhpanpyAnonymousPrePostHooks, PhpanpylistReturnValuesTrait, PhpanpyfixedReturnValueTrait;
public function __construct ($latitude, $longitude, $elevation = 0) {
$args = func_get_args();
$this->firePreHookInstance(__FUNCTION__, ...$args);
parent::__construct($latitude, $longitude, $elevation);
$this->firePostHookInstance(__FUNCTION__, ...$args);
}
public function getLatitude ($radians = false) {
$args = func_get_args();
$this->firePreHookInstance(__FUNCTION__, ...$args);
$result = $this->traitMethodCallReturnNextValueFromList(__FUNCTION__);
$this->firePostHookInstance(__FUNCTION__, $result, ...$args);
return $result;
}
public function getElevation () {
$args = func_get_args();
$this->firePreHookInstance(__FUNCTION__, ...$args);
$result = $this->traitMethodCallReturnFixedValue(__FUNCTION__);
$this->firePostHookInstance(__FUNCTION__, $result, ...$args);
return $result;
}
}
Anonymous Classes: Behind the Mask

More Related Content

PPTX
Anonymous classes2
PPT
Synapseindia object oriented programming in php
PPT
Advanced php
PDF
Object Oriented Programming in PHP
PPT
PHP- Introduction to Object Oriented PHP
PPT
Php object orientation and classes
PDF
09 Object Oriented Programming in PHP #burningkeyboards
PDF
Postobjektové programovanie v Ruby
Anonymous classes2
Synapseindia object oriented programming in php
Advanced php
Object Oriented Programming in PHP
PHP- Introduction to Object Oriented PHP
Php object orientation and classes
09 Object Oriented Programming in PHP #burningkeyboards
Postobjektové programovanie v Ruby

What's hot (20)

PPTX
Ch8(oop)
PDF
A Gentle Introduction To Object Oriented Php
ZIP
Object Oriented PHP5
PPT
core java
PPT
PHP - Introduction to Object Oriented Programming with PHP
PDF
Demystifying Object-Oriented Programming #ssphp16
PPTX
FFW Gabrovo PMG - PHP OOP Part 3
PDF
Python programming : Inheritance and polymorphism
PDF
Object Oriented Programming with PHP 5 - More OOP
PDF
OOP in PHP
PPT
Best Guide for Javascript Objects
PPTX
Object oriented programming with python
PPT
04inherit
PPTX
Basics of Object Oriented Programming in Python
PPTX
Python oop third class
PPT
Oops in PHP
PPT
Class 7 - PHP Object Oriented Programming
PPTX
Object oriented programming in python
KEY
Xtext Eclipse Con
PDF
Hibernate Inheritenc Mapping
Ch8(oop)
A Gentle Introduction To Object Oriented Php
Object Oriented PHP5
core java
PHP - Introduction to Object Oriented Programming with PHP
Demystifying Object-Oriented Programming #ssphp16
FFW Gabrovo PMG - PHP OOP Part 3
Python programming : Inheritance and polymorphism
Object Oriented Programming with PHP 5 - More OOP
OOP in PHP
Best Guide for Javascript Objects
Object oriented programming with python
04inherit
Basics of Object Oriented Programming in Python
Python oop third class
Oops in PHP
Class 7 - PHP Object Oriented Programming
Object oriented programming in python
Xtext Eclipse Con
Hibernate Inheritenc Mapping
Ad

Similar to Anonymous Classes: Behind the Mask (20)

PPTX
Anonymous classes
PPTX
OOP in PHP.pptx
PDF
PHP OOP
PDF
Object Oriented Programming in PHP
PPTX
PDF
Demystifying Object-Oriented Programming - PHP UK Conference 2017
PPTX
PHP 7 - A look at the future
PPTX
Lecture 17 - PHP-Object-Orientation.pptx
PPTX
PHP 5 Magic Methods
PPTX
PHP7 - A look at the future
PPTX
Lecture-10_PHP-OOP.pptx
PPT
UNIT-IV WT web technology for 1st year cs
PPTX
Only oop
PDF
php_final_sy_semIV_notes_vision.pdf
PDF
php_final_sy_semIV_notes_vision (3).pdf
PDF
php_final_sy_semIV_notes_vision.pdf
PDF
php_final_sy_semIV_notes_vision.pdf
PDF
Demystifying Object-Oriented Programming - PHP[tek] 2017
PPTX
Object Oriented Programming Basics with PHP
PPTX
OOP Day 2
Anonymous classes
OOP in PHP.pptx
PHP OOP
Object Oriented Programming in PHP
Demystifying Object-Oriented Programming - PHP UK Conference 2017
PHP 7 - A look at the future
Lecture 17 - PHP-Object-Orientation.pptx
PHP 5 Magic Methods
PHP7 - A look at the future
Lecture-10_PHP-OOP.pptx
UNIT-IV WT web technology for 1st year cs
Only oop
php_final_sy_semIV_notes_vision.pdf
php_final_sy_semIV_notes_vision (3).pdf
php_final_sy_semIV_notes_vision.pdf
php_final_sy_semIV_notes_vision.pdf
Demystifying Object-Oriented Programming - PHP[tek] 2017
Object Oriented Programming Basics with PHP
OOP Day 2
Ad

More from Mark Baker (20)

PPTX
Looping the Loop with SPL Iterators
PPTX
Looping the Loop with SPL Iterators
PPTX
Looping the Loop with SPL Iterators
PPTX
Deploying Straight to Production
PPTX
Deploying Straight to Production
PPTX
Deploying Straight to Production
PPTX
A Brief History of Elephpants
PPTX
Aspects of love slideshare
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
PPTX
A Brief History of ElePHPants
PPTX
Coding Horrors
PPTX
Testing the Untestable
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
PPTX
Coding Horrors
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
PPTX
Giving birth to an ElePHPant
PPTX
A Functional Guide to Cat Herding with PHP Generators
PPTX
A Functional Guide to Cat Herding with PHP Generators
PPTX
SPL - The Undiscovered Library - PHPBarcelona 2015
PPTX
Zephir - A Wind of Change for writing PHP extensions
Looping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
Deploying Straight to Production
Deploying Straight to Production
Deploying Straight to Production
A Brief History of Elephpants
Aspects of love slideshare
Does the SPL still have any relevance in the Brave New World of PHP7?
A Brief History of ElePHPants
Coding Horrors
Testing the Untestable
Does the SPL still have any relevance in the Brave New World of PHP7?
Coding Horrors
Does the SPL still have any relevance in the Brave New World of PHP7?
Giving birth to an ElePHPant
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP Generators
SPL - The Undiscovered Library - PHPBarcelona 2015
Zephir - A Wind of Change for writing PHP extensions

Recently uploaded (20)

PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
System and Network Administraation Chapter 3
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Nekopoi APK 2025 free lastest update
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
Introduction to Artificial Intelligence
PDF
System and Network Administration Chapter 2
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Which alternative to Crystal Reports is best for small or large businesses.pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Upgrade and Innovation Strategies for SAP ERP Customers
VVF-Customer-Presentation2025-Ver1.9.pptx
Softaken Excel to vCard Converter Software.pdf
PTS Company Brochure 2025 (1).pdf.......
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
System and Network Administraation Chapter 3
How Creative Agencies Leverage Project Management Software.pdf
Nekopoi APK 2025 free lastest update
How to Migrate SBCGlobal Email to Yahoo Easily
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Introduction to Artificial Intelligence
System and Network Administration Chapter 2
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
2025 Textile ERP Trends: SAP, Odoo & Oracle
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free

Anonymous Classes: Behind the Mask

  • 2. PHP7 Anonymous Classes • What is an Anonymous Class? • A class that is defined “inline”, within user code, at runtime • Sometimes called “inline” or “nested” classes • Don’t have the scope of the class where they are created • Not assigned a class name
  • 3. PHP7 Anonymous Classes • What is an Anonymous Class? • How do I use an Anonymous Class?
  • 4. PHP7 Anonymous Classes • How do I use an Anonymous Class? • No name given to the class (internally assigned by PHP) • Closing semi-colon (;) • Constructor arguments passed in class definition • All objects created by the same anonymous class declaration are instances of that class (the internal class reference is identical). $objectInstance = new class( 'arguments'... ) { // defined properties and methods };
  • 5. PHP7 Anonymous Classes function locationFormatBuilder (array $location = []) { return new class (...$location) { const POINT_MASK = '% 3d° % 2d' %5.2f" %s'; public function __construct($latitude, $longitude) { $this->latitude = $latitude; $this->longitude = $longitude; } protected function point($point, $orientation) { … return vsprintf(self::POINT_MASK, [$degrees, $minutes, $seconds, $direction]); } public function __toString() { return vsprintf( '%s, %s', [$this->point($this->latitude, ['N','S']), $this->point($this->longitude, ['E','W'])] ); } }; }
  • 6. PHP7 Anonymous Classes $locations = [ [ 51.5074, -0.1278 ], // London [ 40.7128, -74.0059 ], // New York [ -22.9068, -43.1729 ], // Rio de Janeiro [ -33.9249, 18.4241 ], // Cape Town [ 19.0760, 72.8777 ], // Mumbai [ 35.6895, 139.6917 ], // Tokyo [ -33.8688, 151.2093 ], // Sydney [ 31.7683, 35.2137 ], // Jerusalem ]; foreach ($locations as $location) { echo locationFormatBuilder($location), PHP_EOL; }
  • 7. 51° 30' 26.00" N, 0° 7' 40.00" W 40° 42' 46.00" N, 74° 0' 21.00" W 22° 54' 24.00" S, 43° 10' 22.00" W 33° 55' 29.00" S, 18° 25' 26.00" E 19° 4' 33.00" N, 72° 52' 39.00" E 35° 41' 22.00" N, 139° 41' 30.00" E 33° 52' 7.00" S, 151° 12' 33.00" E 31° 46' 5.00" N, 35° 12' 49.00" E PHP7 Anonymous Classes
  • 8. PHP7 Anonymous Classes • How do I use an Anonymous Class? • Can “implement” and “extend” • Can use Traits $objectInstance = new class( 'arguments'... ) { // defined properties and methods };
  • 9. PHP7 Anonymous Classes • Anonymous Class Factories • Builds an Anonymous Class that extends the “userModel” class with optional Traits • Uses “eval()” $anonymousModel = (new AnonymousClassFactory('userModel')) ->withConstructorArguments($databaseConnection) ->withTraits('softDelete', 'auditable') ->create();
  • 10. PHP7 Anonymous Classes trait softDelete { protected $softDelete = true; } trait auditable { protected $auditable = true; } class userModel { protected $dbConnection; protected $loggingEnabled; public function __construct($dbConnection, $loggingEnabled = false) { $this->dbConnection = $dbConnection; $this->loggingEnabled = $loggingEnabled; } }
  • 11. PHP7 Anonymous Classes $dbConnection = new PDO('sqlite:example.db'); $loggingEnabled = true; $className = 'userModel'; $traits = implode(', ', ['softDelete', 'auditable']); $classDefinition = <<<ANONYMOUS new class($dbConnection, $loggingEnabled) extends {$className} { use {$traits}; }; ANONYMOUS; $anonymousUserModelClassInstance = eval("return $classDefinition;");
  • 12. PHP7 Anonymous Classes object(class@anonymous)#2 (4) { ["dbConnection":protected]=> object(PDO)#1 (0) { } ["loggingEnabled":protected]=> bool(true) ["softDelete":protected]=> bool(true) ["auditable":protected]=> bool(true) }
  • 13. PHP7 Anonymous Classes • Anonymous Class Factories • In Search of an Anonymous Class Factory https://markbakeruk.net/2016/05/03/in-search-of-an-anonymous-class-factory/ • Anonymous Class Factory – The Results are in https://markbakeruk.net/2016/05/12/anonymous-class-factory-the-results-are-in/ $anonymousModel = (new AnonymousClassFactory('modelClass')) ->withConstructorArguments($databaseConnection) ->withTraits('softDelete', 'auditable') ->create();
  • 14. PHP7 Anonymous Classes class userController { protected $user; public function __construct(userModel $user) { $this->user = $user; } } $controller = new UserController($anonymousUserModelClassInstance);
  • 15. PHP7 Anonymous Classes • What is an Anonymous Class? • How do I use an Anonymous Class? • What Limitations are there to Anonymous Classes?
  • 16. PHP7 Anonymous Classes • What Limitations are there to Anonymous Classes? • Definition and Instantiation in a Single Step • Cannot be Serialized • Effectively Final • No OpCaching • No Documentation (DocBlocks) • No IDE Hinting
  • 17. PHP7 Anonymous Classes • What is an Anonymous Class? • How do I use an Anonymous Class? • What Limitations are there to Anonymous Classes? • Why would I use Anonymous Classes?
  • 18. PHP7 Anonymous Classes • Why would I use Anonymous Classes? • One-off Objects • Private Classes • Test Mocking • On-demand Typed Structures (instead of generic arrays or StdClass) • Ad-hoc adapters in a loosely coupled architecture • To bypass Autoloading
  • 19. PHP7 Anonymous Classes • Why would I use Anonymous Classes? • Test Mocking • https://mfyu.co.uk/post/anonymous-classes-in-php-7-are-fantastic-for-tests
  • 20. PHP7 Anonymous Classes • Inner- or Nested-Classes class SpyMaster { private $targetObject; protected $objectMission; public function __construct($targetObject) { $this->targetObject = $targetObject; $this->objectMission = new SpyObjectMission($targetObject); } protected function getHandler() { … } public function infiltrate() { return $this->getHandler(); } }
  • 21. PHP7 Anonymous Classes • Inner- or Nested-Classes class SpyObjectMission { public $methods = []; public $invoker; public function __construct($targetObject) { $reflector = new ReflectionObject($targetObject); $this->invoker = $this->getInvoker($reflector, $targetObject); } protected function getInvoker(ReflectionObject $reflector, $targetObject) { $staticMethods = array_column($reflector->getMethods(ReflectionMethod::IS_STATIC), 'name’); $this->methods = array_diff( array_column($reflector->getMethods(), 'name’), $staticMethods) ); $invoker = function($methodName, ...$args) { return self::$methodName(...$args); }; return $invoker->bindTo($targetObject, get_class($targetObject)); } }
  • 22. PHP7 Anonymous Classes • Inner- or Nested-Classes protected function getHandler() { return new class ($this->objectMission, $this->staticMission) { private $objectMission; public function __construct(SpyObjectMission $objectMission) { $this->objectMission = $objectMission; } public function __call($methodName, $args) { if (in_array($methodName, $this->objectMission->methods)) { $invoker = $this->objectMission->invoker; return $invoker($methodName, ...$args); } throw new Exception("Object Method {$methodName} does not exist"); } }; }
  • 23. PHP7 Anonymous Classes • Inner- or Nested-Classes $test = new classThatWeWantToTest(1, 2, 3); $spy = (new SpyMaster($test)) ->infiltrate(); echo 'SPY FOR TEST #1', PHP_EOL; echo $spy->privateMethodThatWeWantToTest(), PHP_EOL;
  • 24. PHP7 Anonymous Classes • Inner- or Nested-Classes • Closures, Anonymous Classes and an alternative approach to Test Mocking (Part 2) • https://markbakeruk.net/2017/07/30/closures-anonymous-classes-and-an-alternative- approach-to-test-mocking-part-2/ • Closures, Anonymous Classes and an alternative approach to Test Mocking (Part 4) • https://markbakeruk.net/2018/01/23/closures-anonymous-classes-and-an-alternative- approach-to-test-mocking-part-4/
  • 25. PHP7 Anonymous Classes Phpanpy Mock object framework for unit testing Like Mockery https://packagist.org/packages/mockery/mockery
  • 26. PHP7 Anonymous Classes $dummyConstructorArguments = [1,2]; $points = (new PhpanpyAnonymousDoubleFactory('GeodeticLatLong', ...$dummyConstructorArguments)) ->setMethodReturnValuesList([ 'getLatitude' => [51.5074, 40.7128, -22.9068, -33.9249, 19.0760, 35.6895, -33.8688, 31.7683], 'getLongitude' => [-0.1278, -74.0059, -43.1729, 18.4241, 72.8777, 139.6917, 151.2093, 35.2137], ])->setMethodReturnValuesFixed([ 'getElevation' => 0.0 ])->create(); $line = (new PhpanpyAnonymousDoubleFactory('GeodeticLine’)) ->suppressOriginalConstructor() ->setMethodReturnValuesFixed([ 'getNextPoint' => $points ])->create();
  • 27. PHP7 Anonymous Classes try { for($i = 0; $i < 10; ++$i) { $point = $line->getNextPoint(); echo sprintf( "%+ 9.4f %+ 9.4f % 7.4f", $point->getLatitude(), $point->getLongitude(), $point->getElevation() ), PHP_EOL; } } catch (Exception $e) { echo $e->getMessage(); }
  • 28. PHP7 Anonymous Classes new class(...$this->constructorArgs) extends GeodeticLatLong { use PhpanpyAnonymousPrePostHooks, PhpanpylistReturnValuesTrait, PhpanpyfixedReturnValueTrait; public function __construct ($latitude, $longitude, $elevation = 0) { $args = func_get_args(); $this->firePreHookInstance(__FUNCTION__, ...$args); parent::__construct($latitude, $longitude, $elevation); $this->firePostHookInstance(__FUNCTION__, ...$args); } public function getLatitude ($radians = false) { $args = func_get_args(); $this->firePreHookInstance(__FUNCTION__, ...$args); $result = $this->traitMethodCallReturnNextValueFromList(__FUNCTION__); $this->firePostHookInstance(__FUNCTION__, $result, ...$args); return $result; } public function getElevation () { $args = func_get_args(); $this->firePreHookInstance(__FUNCTION__, ...$args); $result = $this->traitMethodCallReturnFixedValue(__FUNCTION__); $this->firePostHookInstance(__FUNCTION__, $result, ...$args); return $result; } }