This response is based on https://wiki.php.net/rfc/anonymous_classes introduced in PHP 7.I translate it into Spanish because the explanation is complete and so we have it for future references.IntroductionFor some time, PHP has offered support for anonymous functions in the form of Closures (closures); this patch1 introduces the same type of functionality for objects of an anonymous class.The ability to create objects of an anonymous class is an established and well used part of object-oriented programming in other languages (i.e., C # and Java).An anonymous class could be used on a named class 2:when class does not need to be documentedwhen class is used only once during executionAn anonymous class is a class without a name (programmed declared). The functionality of the object is no different from that of an object of a class named. They use the existing syntax for classes, but no name [class]:var_dump(new class($i) {
public function __construct($i) {
$this->i = $i;
}
});
Syntax and examplesnew class (argumentos) {definición}
Note: in an earlier version of this RFC, the arguments were after the definition, this has been changed to reflect feedback during the last discussion.$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
Note: The ability to declare and use a builder in an anonymous class is necessary when you must exercise control over the construction.Heritage / TraitsExtending classes works as you expect.It should be noted that an anonymous class offers the same possibilities as a normal class. They can pass arguments through their builders, extend other classes, implement interfaces, and use traits like a normal class:<?php
class Foo {}
$child = new class extends Foo {};
var_dump($child instanceof Foo); // true
Also the traits (trait) work in the same way as in the class definitions named.trait Foo {
public function someMethod() {
return "bar";
}
}
$anonClass = new class {
use Foo;
};
var_dump($anonClass->someMethod()); // string(3) "bar"
ReflectionThe only change in reflection is to add ReflectionClass::isAnonymous().SerializationSerialization is not compatible and an error will occur as well as anonymous functions.Name of internal classThe inner name of an anonymous class is generated with a single reference based on its address.function my_factory_function(){
return new class{};
}
If we run:get_class (my_factory_function ())
return "class @ 0x7fa77f271bd0" even if it is called several times, since it is the same definition. The word "class"it is used by default, but if the anonymous class spreads a class with a name, this will be used:class mine {}
new class extends mine {};
This class name will be "mine@0x7fc4be471000".Multiple anonymous classes created in the same position (e.g., a loop) can be compared to ==but those created in other places will not match as they will have a different name:$identicalAnonClasses = [];
for ($i = 0; $i < 2; $i++) {
$identicalAnonClasses[$i] = new class(99) {
public $i;
public function __construct($i) {
$this->i = $i;
}
};
}
var_dump($identicalAnonClasses[0] == $identicalAnonClasses[1]); // true
$identicalAnonClasses[2] = new class(99) {
public $i;
public function __construct($i) {
$this->i = $i;
}
};
var_dump($identicalAnonClasses[0] == $identicalAnonClasses[2]); // false
Both classes were identical in all senses, apart from their generated name.Use casesThe code tests present the most significant number of cases of use, however, where the anonymous classes are part of a language, they find their reason to be in many cases of use, not just proof. If it is technically correct to use an anonymous class depends almost entirely on an individual application, or even an object that depends on the perspective.Some quick points:The mocking tests become easy as a cake. Create implementations on the go for interfaces, avoiding the use of complex mocking APIs.Keep the use of these classes out of reach (scope) where they are definedAvoid hitting the self-loader (autoloader) for trivial deployments.Adjusting existing classes that only change one thing can make this very easy. Taking an example of the https://github.com/pusher/pusher-http-php#debugging--logging :// PHP 5.x
class MyLogger {
public function log($msg) {
print_r($msg . "\n");
}
}
$pusher->setLogger( new MyLogger() );
// New Hotness
$pusher->setLogger(new class {
public function log($msg) {
print_r($msg . "\n");
}
});
This allowed us to create a new file or place the class definition at the top of the file or somewhere away from its use. For large complex actions, or anything that needs to be reused, that would be better like a class with a name, but in this case it is nice and useful not to bother.If you need to implement a very light interface to create a simple dependency:$subject->attach(new class implements SplObserver {
function update(SplSubject $s) {
printf("Got update from: %s\n", $subject);
}
});
Here is an example, which covers the conversion of middleware PSR-7 to Laravel 5 style middleware.<?php
$conduit->pipe(new class implements MiddlewareInterface {
public function __invoke($request, $response, $next)
{
$laravelRequest = mungePsr7ToLaravelRequest($request);
$laravelNext = function ($request) use ($next, $response) {
return $next(mungeLaravelToPsr7Request($request), $response)
};
$laravelMiddleware = new SomeLaravelMiddleware();
$response = $laravelMiddleware->handle($laravelRequest, $laravelNext);
return mungeLaravelToPsr2Response($response);
}
});
The anonymous classes present the opportunity to create the first type of anity class in PHP. It can nest for slightly different reasons to create an anonymous class, so it deserves a debate:<?php
class Outside {
protected $data;
public function __construct($data) {
$this->data = $data;
}
public function getArrayAccess() {
return new class($this->data) extends Outside implements ArrayAccess {
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetSet($offset, $data) { return ($this->data[$offset] = $data); }
public function offsetUnset($offset) { unset($this->data[$offset]); }
public function offsetExists($offset) { return isset($this->data[$offset]); }
};
}
}
Note: Outer extends not to access $this->datawhich can only be passed to a builder; Outer allows the anaity class to implement the permit ArrayAccess execute protected methods, declared in class Outerin the same $this->dataand by reference, as if they were the class Outer.In the previous simple example, Outer::getArrayAccess take advantage of anonymous classes to declare and create an interface object ArrayAccess for Outer.By making it getArrayAccess be private, you can say that the anonymous class you create is a private class.This increases the chances of grouping the functionality of your objects, can lead to greater legibility, some might say more maintainable code.The alternative to the above is as follows:class Outer implements ArrayAccess {
public $data;
public function __construct($data) {
$this->data;
}
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetSet($offset, $data) { return ($this->data[$offset] = $data); }
public function offsetUnset($offset) { unset($this->data[$offset]); }
public function offsetExists($offset) { return isset($this->data[$offset]); }
}
The reference step is not used in the above examples, so the behavior with respect to $this->data It must be implicit.The way you choose to do it for any specific application, whether getArrayAccess whether private or not, whether by reference or not, depends on the application.Several cases of use have been suggested http://php.markmail.org/message/sxqeqgc3fvs3nlpa?q=anonymous%20classes%20php And here are some.The case of use is the one-time use of a "implementation", where it is currently likely to pass callbacks to a Callback*-class like:$x = new Callback(function() {
/* do something */
});
/* vs */
$x = new class extends Callback {
public function doSometing()
{
/* do something */
}
};
Imagine that you have several abstract methods in an interface/class, which would several callbacks to the builder. Also $this is assigned to the right objects.Cancelling a specific method in a class is a practical use. Instead of creating a new class that expands the original class, you can use an anonymous class and override the methods you want.For example, you can do the following:use Symfony\Component\Process\Process;
$process = new class extends Process {
public function start() {
/* ... */
}
};
Instead of:namespace My\Namespace\Process;
use Symfony\Component\Process\Process as Base;
class Process extends Base {
public function start() {
/* ... */
}
}
$process = new \My\Namespace\Process\Process;
Changes incompatible backwardsNew syntax that will not be analyzed in previous versions, so the BC is not broken.Proposed PHP version (s)7.0Impacted SAPIsAllImpact on Existing ExtensionsNo impact on existing libraries.Open problems (bugs)NoneFuture scopeThe changes made by this patch mean that the named classes are easier to implement (a little bit).ReferencesDiscussion on PHP 7: http://marc.info/?l=php-internals&m=142478600309800&w=2 .Implementation https://github.com/php/php-src/pull/1118 Notes:1 For patch means the introduction of the possibility of anonymous classes in the core of PHP 7.2 You mean a Clase Normal, classic.