You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Collision of interface constant and trait constant doesn't produce fatal error #9271
<?phptrait MyTrait{
constA = 1;
}
interface I{
constA = 2;
}
class D implements I{
use MyTrait;
}
echo D::A;
Resulted in this output:
1
But I expected this output instead:
Fatal error: I and MyTrait define the same constant (A) in the composition of D. However, the definition differs and is considered incompatible. Class was composed in /in/EVuKh on line 10
PHP Version
8.2
Operating System
No response
Reacted by Roman Pronskiy, Ilija Tovilo and Alexandru Pătrănescu
I'm pretty sure this is expected behaviour since the change introduced by https://wiki.php.net/rfc/final_class_const where Interface constants are now override-able by default, and the trait overrides the constants.
One is that class constants inherited from interfaces conflict with trait constants, and the other is that constants introduced into classes from traits can override constants defined in interfaces.
The RFC for trait constants adopts the former, in line with the following behavior for trait properties and class inheritances. https://3v4l.org/84abA
So this is indeed a bug. I have a fix on my end and will PR it later.
I think it shouldn't matter if an interface constant is overridden by a constant defined in an implementing class or in a trait which is used by an implementing class, so I'm fine with the situation we have now (except if final interface constants are overridable).
I would rather recommend a more restrictive behavior as described in the RFC for now.
In the current implementation, trait constants can conflict with constants inherited from parent classes. If trait constants are allowed to override interface constants, then the behavior with inheritance needs to be changed as well.
And if we do so, it would become inconsistent with the current behavior for properties. In other words, the order of application for inheritance and trait usage would be different between constants and properties.
Unless there is a strong demand, I think it is easier and preferable to make the behavior as described in the RFC via merging #9274
Note that I would have no problem if trait constants could override constants in parent classes, as long as the behavior reflects further discussions and considerations in internals.
Although this is a comparatively trivial issue, I think it would be better to have a separate RFC for this change, as it should be consistent with the existing behavior for properties.
And if we do so, it would become inconsistent with the current behavior for properties. In other words, the order of application for inheritance and trait usage would be different between constants and properties.
Yes, we have to choose which we want to be consistent with: in case of properties, the more restrictive behavior makes sense, as they cannot be defined in interfaces. On the other hand, constants can be, and IMO we should continue to allow classes/traits to override them, otherwise we'll have different behavior if a piece of code is added to a class via a trait or directly, which would seem like an unfortunate thing to do:
interface I {
public const CONSTANT = 1;
}
trait T {
public const CONSTANT = 2;
}
// Will trigger a fatal error after https://github.com/php/php-src/pull/9274 is merged
class C1 implements I {
use T;
}
// Will continue to work
class C2 implements I {
public const CONSTANT = 2;
}
Just like in case of #9285, I think the reasoning behind the alteration from the RFC is straightforward and doesn't need too much debate (in the sense of a full RFC process). I'd appreciate the opinion of the release managers though @adoy@TimWolla@ramsey
I would still recommend sticking with the behavior as described in the RFC for the time being, and changing it later if necessary, in a consistent way with the behavior for properties :)
otherwise we'll have different behavior if a piece of code is added to a class via a trait or directly, which would seem like an unfortunate thing to do
The breakage in that situation itself can be also considered as a valid result of a feature keeping consistency of the definitions, which we know as the compatibility checking.
Anyway, if RMs decide to allow trait constants to override constants from interfaces or parents of composing classes, I would like to see a decision on whether to fix the inconsistency with properties or not as well.
interface I {
publicconstCONSTANT = 1;
}
abstractclass A {
publicconstCONSTANT = 1;
}
trait T {
publicconstCONSTANT = 2;
}
// works well, as it shouldclassC1implements I {
publicconstCONSTANT = 2;
}
// works well, as it shouldclassC2extends A {
publicconstCONSTANT = 2;
}
// works well nowclassC3implements I {
use T;
}
// fatal errorclassC4extends A {
use T;
}
I believe it's good to keep it in sync for interface as well. That is what https://wiki.php.net/rfc/final_class_const was fixing as well, the inconsistencies for constants overriding between class extending and interface implementing.
A common RFC to allow them both would be good later, to have the code in sync. Otherwise, if we don't fix them and RFC to allow it for class inheritance with trait overriding would never be approved, we would have an inconsistency forever.
Just to make it clear, I don't think it's bad to keep the behavior we have for interfaces but I don't like the inconsistency it brings in comparison with parent classes. So another option would be to allow Traits implemented in child classes to override non final constants from parent classes and to have this in PHP 8.2.
For inconsistency with properties, that's another story and I don't think that needs to be in sync with constants.
We don't have the same behavior with trait for the class O4, returns:
Fatal error: I1 and T1 define the same constant (C1) in the composition of O4. However, the definition differs and is considered incompatible. Class was composed in /home/user/scripts/code.php on line 32
When I change the traitT1 with the following code, I get the same error:
Activity
iluuu1994 commentedon Aug 8, 2022
@sj-i FYI. Can you take a look? This is an example from the RFC:
However, there is no error here.
Girgias commentedon Aug 8, 2022
I'm pretty sure this is expected behaviour since the change introduced by https://wiki.php.net/rfc/final_class_const where Interface constants are now override-able by default, and the trait overrides the constants.
iluuu1994 commentedon Aug 8, 2022
@Girgias That makes sense. Then the example in the RFC was incorrect (the constants in traits RFC was voted on AFTER the final const RFC).
sj-i commentedon Aug 8, 2022
There are two possible interpretations here.
One is that class constants inherited from interfaces conflict with trait constants, and the other is that constants introduced into classes from traits can override constants defined in interfaces.
The RFC for trait constants adopts the former, in line with the following behavior for trait properties and class inheritances.
https://3v4l.org/84abA
So this is indeed a bug. I have a fix on my end and will PR it later.
kocsismate commentedon Aug 21, 2022
I think it shouldn't matter if an interface constant is overridden by a constant defined in an implementing class or in a trait which is used by an implementing class, so I'm fine with the situation we have now (except if final interface constants are overridable).
sj-i commentedon Aug 21, 2022
I would rather recommend a more restrictive behavior as described in the RFC for now.
In the current implementation, trait constants can conflict with constants inherited from parent classes. If trait constants are allowed to override interface constants, then the behavior with inheritance needs to be changed as well.
And if we do so, it would become inconsistent with the current behavior for properties. In other words, the order of application for inheritance and trait usage would be different between constants and properties.
Unless there is a strong demand, I think it is easier and preferable to make the behavior as described in the RFC via merging #9274
sj-i commentedon Aug 21, 2022
Note that I would have no problem if trait constants could override constants in parent classes, as long as the behavior reflects further discussions and considerations in internals.
Although this is a comparatively trivial issue, I think it would be better to have a separate RFC for this change, as it should be consistent with the existing behavior for properties.
kocsismate commentedon Aug 22, 2022
Yes, we have to choose which we want to be consistent with: in case of properties, the more restrictive behavior makes sense, as they cannot be defined in interfaces. On the other hand, constants can be, and IMO we should continue to allow classes/traits to override them, otherwise we'll have different behavior if a piece of code is added to a class via a trait or directly, which would seem like an unfortunate thing to do:
Just like in case of #9285, I think the reasoning behind the alteration from the RFC is straightforward and doesn't need too much debate (in the sense of a full RFC process). I'd appreciate the opinion of the release managers though @adoy @TimWolla @ramsey
TimWolla commentedon Aug 22, 2022
@kocsismate You likely meant to mention @saundefined, not me.
kocsismate commentedon Aug 22, 2022
Ahh, yes, sorry! :/
sj-i commentedon Aug 22, 2022
I would still recommend sticking with the behavior as described in the RFC for the time being, and changing it later if necessary, in a consistent way with the behavior for properties :)
The breakage in that situation itself can be also considered as a valid result of a feature keeping consistency of the definitions, which we know as the compatibility checking.
Anyway, if RMs decide to allow trait constants to override constants from interfaces or parents of composing classes, I would like to see a decision on whether to fix the inconsistency with properties or not as well.
drealecs commentedon Aug 22, 2022
As now it's an error related to constant for extending a class: https://3v4l.org/14L0Z/rfc#vgit.master
I believe it's good to keep it in sync for interface as well. That is what https://wiki.php.net/rfc/final_class_const was fixing as well, the inconsistencies for constants overriding between class extending and interface implementing.
A common RFC to allow them both would be good later, to have the code in sync. Otherwise, if we don't fix them and RFC to allow it for class inheritance with trait overriding would never be approved, we would have an inconsistency forever.
Just to make it clear, I don't think it's bad to keep the behavior we have for interfaces but I don't like the inconsistency it brings in comparison with parent classes. So another option would be to allow Traits implemented in child classes to override non final constants from parent classes and to have this in PHP 8.2.
For inconsistency with properties, that's another story and I don't think that needs to be in sync with constants.
Renji-FR commentedon Oct 3, 2024
Someone has any update about this bug?
We don't have the same behavior with
traitfor the classO4, returns:When I change the
traitT1 with the following code, I get the same error:Thank you
(Tested with PHP v8.3.10)