Revisiting Anonymous Classes
| From: | Sebastian Bergmann | Date: | Sat, 28 Jun 2014 13:36:48 +0000 |
| Subject: | Revisiting Anonymous Classes | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-75122@lists.php.net to get a copy of this message | ||
In a unit test, test doubles (dummies, fakes, stubs, spys, and mocks)
are used to simulate the behavior of complex, real objects when a
real object is difficult or impossible to incorporate into a unit
test. A test double can be used anywhere in the program where the
program expects an object of the original class.
Traditionally, frameworks and libraries are used to automatically
generate test double objects based on the original objects using
reflection. This idea stems from a time when IDEs were not powerful
enough to do this generation for us.
Quoting Robert C. Martin [1]:
"Stubs and spies are very easy to write. My IDE makes it trivial.
I just point at the interface and tell the IDE to implement it.
Voila! It gives me a dummy. Then I just make a simple modification
and turn it into a stub or a spy. [...]
I don't like the strange syntax of mocking tools, and the
complications they add to my setups. I find writing my own test
doubles to be simpler in most cases."
The more I think about this (especially in the aftermath of the
unserialize() issue), the more it appeals to me to have "real
code", generated in parts by my IDE, for my test doubles.
The question remains, though, where to put this code. Obviously
it belongs with the test suite. But how to name the test double
classes? Unique names are required to be able to have multiple
(differently configured) test doubles for the same original
class. Mocking tools (such as PHPUnit_MockObject, for instance)
use random names for their test double classes.
Anonymous classes could be a solution for this problem.
I was surprised to find [2] (and even more so because I voted "No"
on it ... and had no recollection of reading the RFC or voting
on it). Most likely I did not see a use case for anonymous classes
back then.
I would like to propose the following syntax for declaring an
anonymous class that does not implement an interface or extend
a class:
$o = new {
public function method() {
// ...
}
// ...
};
An anonymous class can extend one class or implement one interface.
Unlike non-anonymous classes, an anonymous class cannot do both.
In other words, it cannot both extend a class and implement an
interface, nor can it implement more than one interface.
The syntax to have an anonymous class implement an interface or
extend a class is the same:
interface AnInterface {
public function method();
}
$o = new AnInterface {
public function method() {
// ...
}
}
class AClass {
public function method()
{
// ...
}
}
$o = new AClass {
// ...
}
The ReflectionClass and ReflectionObject classes need to be adapted
for anonymous classes. Only new syntax elements would be added to
the PHP language. Existing elements of the PHP language syntax would
not be changed. No new reserved words would be added to the PHP
language. There should not be an impact on backwards compatibility.
In case there is enough positive feedback to the syntax proposed in
this email I would gladly write a formal RFC. I could also help with
writing tests and documentation. Unfortunately I cannot implement the
feature myself.
--
[1] http://blog.8thlight.com/uncle-bob/2014/05/14/TheLittleMocker.html
[2] https://wiki.php.net/rfc/anonymous_classes