致命错误:枚举案例值必须是可评估的汇编时间

发布于 2025-02-10 22:51:22 字数 303 浏览 1 评论 0原文

我正在尝试在枚举值中包括一个常数,但是我会得到致命错误枚举案例值必须是compile time可评估(以下是代码):

const PARENT = 'parent';
enum MyEnum:string
{
    case firstChild = PARENT . '_child1';
    case secondChild = PARENT . '_child2';
    
}

我不明白为什么我会得到此错误,因为常数的价值无法改变。 我已经搜索了错误,但我什么也没发现。 有什么想法吗?

I'm trying to include a constant in a Enum value but I get the fatal error Enum case value must be compile-time evaluatable (here's the code) :

const PARENT = 'parent';
enum MyEnum:string
{
    case firstChild = PARENT . '_child1';
    case secondChild = PARENT . '_child2';
    
}

I don't understand why I get this error, because the value of a constant can't change.
I have already Google the error but I have found nothing.
Any idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

⊕婉儿 2025-02-17 22:51:22

PHP中的“编译时间”和“运行时间”之间的区别并不总是很明显,因为我们没有像C或Java这样的语言那样明确地“构建” PHP项目。当也微妙的情况下发生的规则,部分由语言的历史特征支配。

在这种情况下,当处理myenum的定义时, parts 将可用;但这不是 它的工作原理。

如果我们使用普通类做同样的事情,我们可以尝试在行动中看到此操作:

class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
echo Foo::EXAMPLE;

如果您单独运行该代码,您将看到该类是编译的,而没有常数IT引用实际上可用,class_exists呼叫成功。只有当您尝试实际访问foo ::示例 PHP确实尝试评估其所指的全局常数并给出错误(或在较旧版本中,通知或警告)时,只有当您尝试实际访问foo :: exge时(示例

这允许事物加载“以错误的顺序”加载 - 其中任何一个都会成功,即使一个人在“类”之前定义了常数,而一个”之后的“ iT:

define('OTHER_CONST', 'some value');
class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
echo Foo::EXAMPLE;

or::

class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
define('OTHER_CONST', 'some value');
echo Foo::EXAMPLE;

我使用define在这里使这是运行时代码更为明显;例如,它同样可以是包含不同PHP文件中的const行。

关键在于,即使在类定义之前出现常数定义,也没有在汇总类定义时实际评估。首先引用类常数时,它是“在运行时间进行评估”。

回到您的枚举示例,该错误更有意义:尽管恒定的定义恰好出现在文件中,但它的用法未在编译时进行“评估”。与班级常数不同,在编译枚举时,总是计算出背景案例的值,因此不能包含对直到运行时不存在的事物的引用,不幸的是包括全局常数。

但是,一个小的修改确实有效:

class Something
{
    const PARENT = 'parent';
}
enum MyEnum:string
{
    case firstChild = Something::PARENT . '_child1';
    case secondChild = Something::PARENT . '_child2';
    
}

这有效,因为在这种情况下,可以在编译时评估类常数本身,然后在编译枚举定义时可用。

为了使事物全圈,这将不是 的工作:

const GRAND_PARENT = 'parent';

class Something
{
    const PARENT = GRAND_PARENT;
}
enum MyEnum:string
{
    case firstChild = Something::PARENT . '_child1';
    case secondChild = Something::PARENT . '_child2';
    
}
var_dump(class_exists('MyEnum'));
echo MyEnum::firstChild->value;

在这里,全局常数被认为是一个运行时值,因此将类常数推迟到运行时;汇编枚举时,它试图获取类常数但不能拿出类的值,因此会出现错误。

The distinction between "compile-time" and "run-time" in PHP is not always obvious, because we don't explicitly "build" a PHP project like we would with a language like C or Java. The rules of what happens when are also subtle, and governed partly by historical features of the language.

In this case, it looks like the constant PARENT would be available when the definition of MyEnum was being processed; but that's not quite how it works.

If we do the same thing with a normal class, we can try to see this in action:

class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
echo Foo::EXAMPLE;

If you run that code on its own, you will see that the class is compiled without the constant it references actually being available, and the class_exists call succeeds. Only when you try to actually access Foo::EXAMPLE does PHP try to evaluate the global constant it refers to, and gives an error (or, in older versions, a Notice or Warning).

That allows things to load "in the wrong order" - either of these will succeed, even though one defines the constant "before" the class, and one "after" it:

define('OTHER_CONST', 'some value');
class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
echo Foo::EXAMPLE;

or:

class Foo {
    const EXAMPLE = OTHER_CONST;
}
var_dump(class_exists('Foo'));
define('OTHER_CONST', 'some value');
echo Foo::EXAMPLE;

I've used define here to make it more obvious that this is run-time code; it could equally be a const line in a different PHP file being included, for instance.

The key here is that even if the constant definition appears before the class definition, it's not actually evaluated when the class definition is being compiled. It is "evaluated at run-time" when the class constant is first referenced.

Coming back to your enum example, the error makes a bit more sense: although the constant definition happens to appear first in the file, uses of it are not "evaluated at compile time". Unlike class constants, the values of backed enum cases are always calculated while the enum is being compiled, so can't contain references to things that won't exist until run-time, which unfortunately includes global constants.

However, a small modification does work:

class Something
{
    const PARENT = 'parent';
}
enum MyEnum:string
{
    case firstChild = Something::PARENT . '_child1';
    case secondChild = Something::PARENT . '_child2';
    
}

This works because in this case the class constant itself can be evaluated at compile-time, and will then be available when the enum definition is compiled.

To bring things full-circle, this will not work:

const GRAND_PARENT = 'parent';

class Something
{
    const PARENT = GRAND_PARENT;
}
enum MyEnum:string
{
    case firstChild = Something::PARENT . '_child1';
    case secondChild = Something::PARENT . '_child2';
    
}
var_dump(class_exists('MyEnum'));
echo MyEnum::firstChild->value;

Here, the global constant is considered a run-time value, so the class constant is deferred until run-time; when the enum is compiled, it tries to fetch the class constant's value but can't, so gives an error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文