PHP 中的静态类初始值设定项
我有一个带有一些静态函数的辅助类。类中的所有函数都需要一个“重”初始化函数来运行一次(就像它是一个构造函数一样)。
有实现这一目标的良好实践吗?
我唯一想到的就是调用一个 init 函数,如果它已经运行过一次(使用静态 $initialized var),则中断它的流程。问题是我需要在类的每个函数上调用它。
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 init
function, and breaking its flow if it has already run once (using a static $initialized
var). The problem is that I need to call it on every one of the class’s functions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
听起来单例比一堆静态方法更适合你
然后,在使用中
Sounds like you'd be better served by a singleton rather than a bunch of static methods
And then, in usage
这样,初始化就会在包含类文件时发生。您可以通过使用自动加载来确保这种情况仅在必要时发生(并且仅发生一次)。
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.
实际上,我在需要初始化(或至少需要执行一些代码)的静态类上使用公共静态方法 __init__() 。然后,在我的自动加载器中,当它加载一个类时,它会检查 is_callable($class, '__init__') 。如果是,则调用该方法。快速、简单、有效...
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 checksis_callable($class, '__init__')
. If it is, it calls that method. Quick, simple and effective...注意:这正是OP所说的。(但没有显示代码。)我在此处显示了详细信息,以便您可以将其与已接受的答案进行比较。我的观点是,恕我直言,OP 最初的直觉比他接受的答案更好。
考虑到所接受的答案得到了高度评价,我想指出静态方法一次性初始化的“天真的”答案,几乎不比 Singleton 的实现更多代码——并且有一个重要的优势< /强>。
这种方法的优点是,您可以使用简单的静态函数语法进行调用:将
其与接受的答案所需的调用进行对比:
作为一般原则,最好支付当您编写类时,编码价格一次,以使调用者更简单。
如果您不使用 PHP 7.4 的
opcode.cache
,则使用 < a href="https://stackoverflow.com/a/3312881/199364">维克多·尼科莱的回答。简单的。无需额外编码。无需理解“高级”编码。 (我建议包括 FrancescoMM 的评论,以确保“init”永远不会执行两次。)请参阅 Szczepan 的解释,了解 Victor 技术的原因不适用于opcode.cache
。如果您正在使用
opcode.cache
,那么据我所知,我的答案是您能得到的最干净的答案。成本只是在每个公共方法的开头添加行MyClass::init();
。注意:如果您想要公共属性,请将它们编码为get
/set
方法对,以便您可以添加<代码>init调用。(私有成员不需要
init
调用,因为它们无法从外部访问 - 因此某些公共方法已经被调用,由执行时间到达私有成员。)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.
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.
The advantage of this approach, is that you get to call with the straightforward static function syntax:
Contrast it to the calls required by the accepted answer:
As a general principle, it is best to pay the coding price once, when you code a class, to keep callers simpler.
If you are NOT using PHP 7.4's
opcode.cache
, then use 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.) See Szczepan's explanation of why Victor's technique won't work withopcode.cache
.If you ARE using
opcode.cache
, then AFAIK my answer is as clean as you can get. The cost is simply adding the lineMyClass::init();
at start of every public method. NOTE: If you want public properties, code them as aget
/set
pair of methods, so that you have a place to add thatinit
call.(Private members do NOT need that
init
call, as they are not reachable from the outside - so some public method has already been called, by the time execution reaches the private member.)有一种方法可以调用一次
init()
方法并禁止其使用,您可以将该函数转换为私有初始值设定项并在类声明后调用它,如下所示: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:我将此作为答案发布,因为从 PHP 7.4 开始这非常重要。
PHP 7.4 的
opcache.preload
机制使得预加载类的操作码成为可能。如果您使用它来预加载包含类定义和一些副作用的文件,则该文件中定义的类将“存在”于此 FPM 服务器及其工作人员执行的所有后续脚本,但是副作用不会生效,并且自动加载器将不需要包含它们的文件,因为该类已经“存在”。这完全击败了任何依赖于在包含类定义的文件中执行顶级代码的静态初始化技术。I am posting this as an answer because this is very important as of PHP 7.4.
The
opcache.preload
mechanism 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 and some 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.这是 Victor Nicollet 和 ToolmakerSteve 两个答案的变体,旨在解决其中的一些问题,并消除在接受的答案中描述的单例模式中调用方法的稍微复杂的要求。也就是说,这种方法是:
公共
只需像平常一样调用任何私有方法,它们就会运行
_init()
如果需要:This is a variation of both answers by Victor Nicollet and ToolmakerSteve which seeks to solve some of the problems therein as well as eliminate the slightly more complex requirement of calling methods in the singleton pattern described in the accepted answer. Namely this approach is:
opcode.cache
and does not require any initializing function call outside of the class itselfinit()
inside every method.public
Simply call any of the private methods as you normally would and they will run
_init()
if needed:如果您不喜欢
public
静态初始化程序,反射可以是一种解决方法。If you don't like
public
static initializer, reflection can be a workaround.分配静态公共属性的一些测试:
settings.json:
现在我们要向我们的类添加设置公共静态属性,
现在我们测试此代码:
此返回:
然后,如果我们像这样修改类测试:
此返回:
我实际上需要使用公共静态属性初始化一个对象,我将在许多其他类中重用该对象,我认为这是应该的,我不想在我需要的每个方法中执行 new api() ,例如检查主机网站或指出。另外,我想让事情变得更加动态,这样我就可以向 API 添加尽可能多的设置,而不必在初始化类中声明它们。
我见过的所有其他方法都不再在 php > 下工作7.4
我一直在寻找这个问题的解决方案。
Some tests of assigning static public properties :
settings.json :
now we want to add settings public static properties to our class
ok now we test this code :
this return :
Then if we modify the class test like this :
this return :
I actually need to initialize an object with public static properties that I will reuse in many other classes, which I think is supposed to, I don't want to do new api() in every method where I would need, for example to check the host of the site or indicate it. Also I would like to make things more dynamic so that I can add as many settings as I want to my API, without having to declare them in my initialization class.
All other methods I've seen no longer work under php > 7.4
I keep looking for a solution for this problem.
注意 - 提出此建议的 RFC 仍处于草案状态。
建议 PHP 7.x(请参阅 https://wiki.php.net/rfc/static_class_constructor )
Note - the RFC proposing this is still in the draft state.
proposed for PHP 7.x (see https://wiki.php.net/rfc/static_class_constructor )