匿名类
匿名类很有用,可以创建一次性的简单对象。
<?php
// 使用显性类
class Logger
{
public function log($msg)
{
echo $msg;
}
}
$util->setLogger(new Logger());
// 使用匿名类
$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
可以传递参数到匿名类的构造器,也可以继承其他类、实现接口(implement interface),以及像其他普通的类一样使用 trait:
<?php
class SomeClass {}
interface SomeInterface {}
trait SomeTrait {}
var_dump(new class(10) extends SomeClass implements SomeInterface {
private $num;
public function __construct($num)
{
$this->num = $num;
}
use SomeTrait;
});
以上示例会输出:
object(class@anonymous)#1 (1) { ["Command line code0x104c5b612":"class@anonymous":private]=> int(10) }
匿名类被嵌套进普通 Class 后,不能访问这个外部类(Outer class)的 private(私有)、protected(受保护)方法或者属性。 为了访问外部类(Outer class)protected 属性或方法,匿名类可以 extend(扩展)此外部类。 为了使用外部类(Outer class)的 private 属性,必须通过构造器传进来:
<?php
class Outer
{
private $prop = 1;
protected $prop2 = 2;
protected function func1()
{
return 3;
}
public function func2()
{
return new class($this->prop) extends Outer {
private $prop3;
public function __construct($prop)
{
$this->prop3 = $prop;
}
public function func3()
{
return $this->prop2 + $this->prop3 + $this->func1();
}
};
}
}
echo (new Outer)->func2()->func3();
以上示例会输出:
6
声明的同一个匿名类,所创建的对象都是这个类的实例。
<?php
function anonymous_class()
{
return new class {};
}
if (get_class(anonymous_class()) === get_class(anonymous_class())) {
echo 'same class';
} else {
echo 'different class';
}
以上示例会输出:
same class
注意:
注意,匿名类的名称是通过引擎赋予的,如下例所示。 由于实现的细节,不应该去依赖这个类名。
<?php
echo get_class(new class {});以上示例的输出类似于:
class@anonymous/in/oNi1A0x7f8636ad2021
只读匿名类
自 PHP 8.3.0 起,readonly
修饰符可应用于匿名类。
示例 #1 定义 readonly 匿名类
<?php
// 使用匿名类
$util->setLogger(new readonly class('[DEBUG]') {
public function __construct(private string $prefix)
{
}
public function log($msg)
{
echo $this->prefix . ' ' . $msg;
}
});
+添加备注
用户贡献的备注 8 notes
Anonymous ¶
8 years ago
Below three examples describe anonymous class with very simple and basic but quite understandable example
<?php
// First way - anonymous class assigned directly to variable
$ano_class_obj = new class{
public $prop1 = 'hello';
public $prop2 = 754;
const SETT = 'some config';
public function getValue()
{
// do some operation
return 'some returned value';
}
public function getValueWithArgu($str)
{
// do some operation
return 'returned value is '.$str;
}
};
echo "\n";
var_dump($ano_class_obj);
echo "\n";
echo $ano_class_obj->prop1;
echo "\n";
echo $ano_class_obj->prop2;
echo "\n";
echo $ano_class_obj::SETT;
echo "\n";
echo $ano_class_obj->getValue();
echo "\n";
echo $ano_class_obj->getValueWithArgu('OOP');
echo "\n";
echo "\n";
// Second way - anonymous class assigned to variable via defined function
$ano_class_obj_with_func = ano_func();
function ano_func()
{
return new class {
public $prop1 = 'hello';
public $prop2 = 754;
const SETT = 'some config';
public function getValue()
{
// do some operation
return 'some returned value';
}
public function getValueWithArgu($str)
{
// do some operation
return 'returned value is '.$str;
}
};
}
echo "\n";
var_dump($ano_class_obj_with_func);
echo "\n";
echo $ano_class_obj_with_func->prop1;
echo "\n";
echo $ano_class_obj_with_func->prop2;
echo "\n";
echo $ano_class_obj_with_func::SETT;
echo "\n";
echo $ano_class_obj_with_func->getValue();
echo "\n";
echo $ano_class_obj_with_func->getValueWithArgu('OOP');
echo "\n";
echo "\n";
// Third way - passing argument to anonymous class via constructors
$arg = 1; // we got it by some operation
$config = [2, false]; // we got it by some operation
$ano_class_obj_with_arg = ano_func_with_arg($arg, $config);
function ano_func_with_arg($arg, $config)
{
return new class($arg, $config) {
public $prop1 = 'hello';
public $prop2 = 754;
public $prop3, $config;
const SETT = 'some config';
public function __construct($arg, $config)
{
$this->prop3 = $arg;
$this->config =$config;
}
public function getValue()
{
// do some operation
return 'some returned value';
}
public function getValueWithArgu($str)
{
// do some operation
return 'returned value is '.$str;
}
};
}
echo "\n";
var_dump($ano_class_obj_with_arg);
echo "\n";
echo $ano_class_obj_with_arg->prop1;
echo "\n";
echo $ano_class_obj_with_arg->prop2;
echo "\n";
echo $ano_class_obj_with_arg::SETT;
echo "\n";
echo $ano_class_obj_with_arg->getValue();
echo "\n";
echo $ano_class_obj_with_arg->getValueWithArgu('OOP');
echo "\n";
echo "\n";
ytubeshareit at gmail dot com ¶
7 years ago
Anonymous classes are syntax sugar that may appear deceiving to some.
The 'anonymous' class is still parsed into the global scope, where it is auto assigned a name, and every time the class is needed, that global class definition is used. Example to illustrate....
The anonymous class version...
<?php
function return_anon(){
return new class{
public static $str="foo";
};
}
$test=return_anon();
echo $test::$str; //ouputs foo
//we can still access the 'anon' class directly in the global scope!
$another=get_class($test); //get the auto assigned name
echo $another::$str; //outputs foo
?>
The above is functionally the same as doing this....
<?php
class I_named_this_one{
public static $str="foo";
}
function return_not_anon(){
return 'I_named_this_one';
}
$clzz=return_not_anon();//get class name
echo $clzz::$str;
?>
sebastian.wasser at gmail ¶
6 years ago
I wanted to share my findings on static properties of anonymous classes.
So, given an anonymous class' object generating function like this:
<?php
function nc () {
return new class {
public static $prop = [];
};
}
?>
Getting a new object and changing the static property:
<?php
$a = nc();
$a::$prop[] = 'a';
var_dump($a::$prop);
// array(1) {
// [0] =>
// string(1) "a"
// }
?>
Now getting another object and changing the static property will change the original one, meaning that the static property is truly static:
<?php
$b = nc();
$b::$prop[] = 'b';
var_dump($b::$prop); // Same as var_dump($a::$prop);
// array(2) {
// [0] =>
// string(1) "a"
// [1] =>
// string(1) "b"
// }
assert($a::$prop === $b::$prop); // true
?>
joey ¶
5 years ago
The only way to type hint this would appear to be as object.
If you need multiple instances of an anonymous class in a function you can use:
$class = function(string $arg):object {
return new class($arg) {
public function __construct(string $arg) {
$this->ow = $arg;
}
};
};
Though for the sake of structure it's ill advised to do something like this outside of a single scope or that's used across multiple files. If you class is only used in one scope however then it's probably not a code mess problem.
j.m \ jamesweb \ ca ¶
7 years ago
/* I like the idea of OneShot classes.
Thanks to that Anonymous bro\sist for precising
new class( $a, $b )
¯¯¯¯¯¯¯¯¯
If you are looking for "Delayed OneShot Anonymous Classes" for any reason (like the reason: loading files in a readable manner while not using autoload), it would probably look something like this; */
$u = function()use(&$u){
$u = new class{private $name = 'Utils';};
};
$w = function(&$rewrite)use(&$w){
$w = null;
$rewrite = new class{private $name = 'DataUtils';};
};
// Usage;
var_dump(
array(
'Delayed',
'( Self Destructive )',
'Anonymous Class Creation',
array(
'Before ( $u )' => $u,
'Running ( $u() )' => $u(),
'After ( $u )' => $u,
),
0,0,
0,0,
0,0,
'Delayed',
'( Overwriting && Self Destructive )',
'Anonymous Class Creation',
array(
'Before ( $w )' => $w,
'Running ( $w($u) )' => $w($u),
'After ( $w )' => $w,
'After ( $u )' => $u
)
)
);
// btw : oh shoot I failed a spam challenge
razvan_bc at yahoo dot com ¶
4 years ago
you can try these
<?php
$oracle=&$_['nice_php'];
$_['nice_php']=(function(){
return new class{
public static function say($msg){
echo $msg;
}
public static function sp(){
echo self::say(' ');
}
};
});
/*
$_['nice_php']()::say('Hello');
$_['nice_php']()::sp();
$_['nice_php']()::say('World');
$_['nice_php']()::sp();
$_['nice_php']()::say('!');
//almost the same code bottom
*/
$oracle()::say('Hello');
$oracle()::sp();
$oracle()::say('World');
$oracle()::sp();
$oracle()::say('!');
?>
piotr at maslosoft dot com ¶
7 years ago
Please note that class name returned by `get_class` might contain null bytes, as is the case in my version of PHP (7.1.4).
Name will change when class starting line or it's body is changed.
Yes, name is implementation detail that should not be relied upon, but in some rare use cases it is required (annotating anonymous class).
ismaelj+php at hotmail dot com ¶
6 months ago
Thanks to the new property hooks in PHP 8.4 (https://wiki.php.net/rfc/property-hooks) and anonymous functions, now we can create an inner class instantiated only on use:
<?php
class BaseClass {
public function __construct() { echo "base class\n"; }
public $childClass { set {} get {
if ($this->childClass === null ) {
$this->childClass = new class {
public function __construct() { echo " child class\n"; }
public function say(string $s) : void { echo " $s\n"; }
};
}
return $this->childClass;
}
}
}
$base = new BaseClass();
$base->childClass->say('Hello');
$base->childClass->say('World');
/*
Output:
base class
child class
Hello
World
*/
?>
The obvious downside is that you can't set a type to the child class, unless you define an interface and the child class implements it or if the child class extends an existing class:
<?php
class ParentClass {
public function say(string $s) : void { echo " $s\n"; }
}
class BaseClass {
public function __construct() { echo "base class\n"; }
public ParentClass $childClass { set {} get {
if (!isset($this->childClass)) {
$this->childClass = new class extends ParentClass {
public function __construct() { echo " child class\n"; }
};
}
return $this->childClass;
}
}
}
$base = new BaseClass();
$base->childClass->say('Hello');
$base->childClass->say('World');
/*
Output:
base class
child class
Hello
World
*/
?>
?>
This can be also done with functions, but with hooks to me looks more like in other languages that have this functionality natively.
备份地址:http://www.lvesu.com/blog/php/language.oop5.anonymous.php