PHP 中的静态类初始化器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3312806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Static class initializer in PHP
提问by user258626
I have an helper class with some static functions. All the functions in the class require a ‘heavy' initialization function to run once (as if it were a constructor).
我有一个带有一些静态函数的辅助类。类中的所有函数都需要一个“重”初始化函数来运行一次(就像它是一个构造函数)。
Is there a good practice for achieving this?
有没有实现这一目标的好做法?
The only thing I thought of was calling an initfunction, and breaking its flow if it has already run once (using a static $initializedvar). The problem is that I need to call it on every one of the class's functions.
我唯一想到的是调用一个init函数,如果它已经运行过一次(使用静态变量),就中断它的流程$initialized。问题是我需要在类的每个函数上调用它。
回答by Peter Bailey
Sounds like you'd be better served by a singleton rather than a bunch of static methods
听起来像你最好用一个单例而不是一堆静态方法来服务
class Singleton
{
/**
*
* @var Singleton
*/
private static $instance;
private function __construct()
{
// Your "heavy" initialization stuff here
}
public static function getInstance()
{
if ( is_null( self::$instance ) )
{
self::$instance = new self();
}
return self::$instance;
}
public function someMethod1()
{
// whatever
}
public function someMethod2()
{
// whatever
}
}
And then, in usage
然后,在使用中
// As opposed to this
Singleton::someMethod1();
// You'd do this
Singleton::getInstance()->someMethod1();
回答by Victor Nicollet
// file Foo.php
class Foo
{
static function init() { /* ... */ }
}
Foo::init();
This way, the initialization happens when the class file is included. You can make sure this only happens when necessary (and only once) by using autoloading.
这样,当包含类文件时就会进行初始化。您可以通过使用自动加载来确保这仅在必要时(并且仅一次)发生。
回答by ircmaxell
Actually, I use a public static method __init__()on my static classes that require initialization (or at least need to execute some code). Then, in my autoloader, when it loads a class it checks is_callable($class, '__init__'). If it is, it calls that method. Quick, simple and effective...
实际上,我__init__()在需要初始化(或至少需要执行一些代码)的静态类上使用了公共静态方法。然后,在我的自动加载器中,当它加载一个类时,它会检查is_callable($class, '__init__'). 如果是,则调用该方法。快速、简单、有效...
回答by brzuchal
There is a way to call the init()method once and forbid it's usage, you can turn the function into private initializer and ivoke it after class declaration like this:
有一种方法可以调用init()一次该方法并禁止其使用,您可以将函数转换为私有初始化程序并在类声明后调用它,如下所示:
class Example {
private static function init() {
// do whatever needed for class initialization
}
}
(static function () {
static::init();
})->bindTo(null, Example::class)();
回答by ToolmakerSteve
NOTE: This is exactly what OP said they did.(But didn't show code for.) I show the details here, so that you can compare it to the accepted answer. My point is that OP's original instinct was, IMHO, better than the answer he accepted.
注意:这正是 OP 所说的。(但没有显示代码。)我在这里显示了详细信息,以便您可以将其与接受的答案进行比较。我的观点是 OP 的本能是,恕我直言,比他接受的答案要好。
Given how highly upvoted the accepted answer is, I'd like to point out the "naive" answer to one-time initialization of static methods, is hardly more code than that implementation of Singleton -- and has an essential advantage.
考虑到接受的答案的投票率有多高,我想指出静态方法一次性初始化的“天真”答案,几乎没有比单例的实现更多的代码 - 并且具有本质优势。
final class MyClass {
public static function someMethod1() {
MyClass::init();
// whatever
}
public static function someMethod2() {
MyClass::init();
// whatever
}
private static $didInit = false;
private static function init() {
if (!self::$didInit) {
self::$didInit = true;
// one-time init code.
}
}
// private, so can't create an instance.
private function __construct() {
// Nothing to do - there are no instances.
}
}
The advantage of this approach,is that you get to call with the straightforward static function syntax:
这种方法的优点是您可以使用简单的静态函数语法进行调用:
MyClass::someMethod1();
Contrast it to the calls required by the accepted answer:
将其与接受的答案所需的调用进行对比:
MyClass::getInstance->someMethod1();
As a general principle, it is best to pay the coding price once, when you code a class, to keep callers simpler.
作为一般原则,最好在对类进行编码时支付一次编码费用,以使调用者更简单。
Of all the answers (including this one), I prefer Victor Nicollet's answer. Simple. No extra coding required. No "advanced" coding to understand. (I recommend including FrancescoMM's comment, to make sure "init" will never execute twice.)
在所有答案(包括这个)中,我更喜欢Victor Nicollet 的答案。简单的。不需要额外的编码。没有要理解的“高级”编码。(我建议包括 FrancescoMM 的评论,以确保“init”永远不会执行两次。)
So I could have not bothered to write this answer. But so many people upvoted the accepted answer, that I conclude some people are simply not aware of the obvious, "naive", approach (that I show here). Understand this as a starting point.
所以我可以不费心写这个答案。但是这么多人赞成接受的答案,我得出的结论是有些人根本没有意识到明显的“幼稚”方法(我在这里展示)。理解这一点作为起点。
回答by Szczepan Ho?yszewski
I am posting this as an answer because this is very important as of PHP 7.4.
我将此作为答案发布,因为这在 PHP 7.4 中非常重要。
The opcache.preloadmechanism of PHP 7.4 makes it possible to preload opcodes for classes. If you use it to preload a file that contains a class definition andsome side effects, then classes defined in that file will "exist" for all subsequent scripts executed by this FPM server and its workers, but the side effects will not be in effect, and the autoloader will not require the file containing them because the class already "exists". This completely defeats any and all static initialization techniques that rely on executing top-level code in the file that contains the class definition.
opcache.preloadPHP 7.4的机制使得为类预加载操作码成为可能。如果您使用它来预加载包含类定义和一些副作用的文件,则该文件中定义的类将“存在”用于此 FPM 服务器及其工作程序执行的所有后续脚本,但副作用不会生效,并且自动加载器将不需要包含它们的文件,因为该类已经“存在”。这完全击败了任何依赖于在包含类定义的文件中执行顶级代码的静态初始化技术。
回答by Takahiko Kawasaki
If you don't like publicstatic initializer, reflection can be a workaround.
如果您不喜欢public静态初始值设定项,反射可以是一种解决方法。
<?php
class LanguageUtility
{
public static function initializeClass($class)
{
try
{
// Get a static method named 'initialize'. If not found,
// ReflectionMethod() will throw a ReflectionException.
$ref = new \ReflectionMethod($class, 'initialize');
// The 'initialize' method is probably 'private'.
// Make it accessible before calling 'invoke'.
// Note that 'setAccessible' is not available
// before PHP version 5.3.2.
$ref->setAccessible(true);
// Execute the 'initialize' method.
$ref->invoke(null);
}
catch (Exception $e)
{
}
}
}
class MyClass
{
private static function initialize()
{
}
}
LanguageUtility::initializeClass('MyClass');
?>
回答by abcd
Note - the RFC proposing this is still in the draft state.
注意 - 提出此建议的 RFC 仍处于草案状态。
class Singleton
{
private static function __static()
{
//...
}
//...
}
proposed for PHP 7.x (see https://wiki.php.net/rfc/static_class_constructor)
建议用于 PHP 7.x(参见https://wiki.php.net/rfc/static_class_constructor)

