Php class public const

PHP RFC: Typed class constants

Despite the huge efforts put into improving the type system of PHP year after year, it is still not possible to declare constant types. This is less of a concern for global constants, but can indeed be a source of bugs and confusion for class constants:

By default, child classes can override class constants of their parents, so sometimes it is not easy to assume what the value and the type of a class constant really is, unless either their defining class or the constant itself is final:

interface I { const TEST = "Test"; // We may naively assume that the TEST constant is always a string } class Foo implements I { const TEST = []; // But it may be an array. } class Bar extends Foo { const TEST = null; // Or null }

As demonstrated above, it may come in handy to restrict the type of class constants without making them final .

Proposal

This RFC proposes to add support for declaring class, interface, trait, as well as enum constant types (collectively called “class constants” from now on for the sake of simplicity):

enum E { const string TEST = "Test1"; // E::TEST is a string } trait T { const string TEST = E::TEST; // T::TEST is a string too } interface I { const string TEST = E::TEST; // I::TEST is a string as well } class Foo implements I { use T; const string TEST = E::TEST; // Foo::TEST must also be a string } class Bar extends Foo { const string TEST = "Test2"; // Bar::TEST must also be a string, but the value can change }

Supported types

Class constant type declarations support all type declarations supported by PHP, with the exception of void , callable , never .

Читайте также:  Испытание восход солнца html academy

The void , callable types are not supported due to the issues discussed in the typed properties v2 RFC. Similarly to the previous types, never is not applicable in the context of constants.

Strict and coercive typing modes

The strict_types mode has no impact on the behavior since type checks are always performed in strict mode. This is consistent with the default value handing of typed properties.

Inheritance and variance

Class constants are covariant. This means that the type of a class constant is not allowed to be widen during inheritance. If the parent class constant is private, then the type may change arbitrarily. Besides the exceptions mentioned in the previous section, all other types are supported, including union, intersection, as well as DNF types. Some examples:

trait T { public const ?array E = []; } class Test Stringable class Test2 extends Test Stringable public const (Foo&Stringable) enum E { // This is legal since constants provide a covariant context public const static A = E::Foo; case Foo; } class Foo implements Stringable { public function __toString() { return ""; } }

The reason why class constant types are covariant is that they are read-only.

Constant values

Constant values have to match the type of the class constant. The only exception is that float class constants also accept integer values, consistent with the handling of parameter/property types.

The following code illustrates legal and illegal constant values:

class Test  // this is legal public const string A = 'a'; public const int B = 1; public const float C = 1.1; public const bool D = true; public const array E = ['a', 'b']; // this is legal public const iterable F = ['a', 'b']; public const mixed G = 1; public const string

If the constant value is a non compile-time evaluable initializer expression, it is not checked at compile-time. Instead, it will be checked during constant-updating, which will either occur when an object of the class is instantiated or when the class constant is being fetched. As such, the following code is legal:

class Test { public const int TEST1 = C; } define('C', 1); // this prints 1 echo Test::TEST;

If the constant has an illegal type, a TypeError exception is thrown during the object new Test() instantiation or when the class constant Test::TEST is being fetched.

Reflection

The ReflectionClassConstant class is extended with two methods:

class ReflectionClassConstant implements Reflector { . public function getType(): ?ReflectionType {} public function hasType(): bool {} }

hasType() returns true if the class constant has a type, and false otherwise. The behavior matches that of getType() / hasType() for parameters/properties and getReturnType() / hasReturnType() for return types.

Backwards incompatible changes

Impact on extensions

To preserve backwards compatibility with extensions, a new function zend_declare_typed_class_constant() is introduced while keeping the original zend_declare_class_constant_ex() function intact.

Future scope

Currently, the value of class constants cannot be an instance of their own declaring class. In order to illustrate the problem better, here is an example of such code:

class A { public const CONST1 = C; } const C = new A(); // Error: Undefined constant "C"

This is a not-yet well-known limitation of PHP RFC: New in initializers. In the context of the current RFC , this means that self , static , or the class name itself ( A ) is not possible to use with class constants in practice. On the other hand, the above mentioned types can be used with enums:

enum E { public const E CONST1 = E::Foo; public const self CONST2 = E::Foo; public const static CONST3 = E::Foo; case Foo; }

Vote

The proposal needs 2/3 majority to be accepted. Voting is open until 2023-03-13.

Источник

Php class public const

Константы также могут быть объявлены в пределах одного класса. Область видимости констант по умолчанию public .

Замечание:

Константы класса могут быть переопределены дочерним классом. Начиная с PHP 8.1.0, константы класса не могут быть переопределены дочерним классом, если он определён как окончательный (final).

Интерфейсы также могут содержать константы . За примерами обращайтесь к разделу об интерфейсах.

К классу можно обратиться с помощью переменной. Значение переменной не может быть ключевым словом (например, self , parent и static ).

Обратите внимание, что константы класса задаются один раз для всего класса, а не отдельно для каждого созданного объекта этого класса.

Пример #1 Объявление и использование константы

class MyClass
const CONSTANT = ‘значение константы’ ;

function showConstant () echo self :: CONSTANT . «\n» ;
>
>

echo MyClass :: CONSTANT . «\n» ;

$classname = «MyClass» ;
echo $classname :: CONSTANT . «\n» ;

$class = new MyClass ();
$class -> showConstant ();

Специальная константа ::class , которой на этапе компиляции присваивается полное имя класса, полезна при использовании с классами, использующими пространства имён.

Пример #2 Пример использования ::class с пространством имён

Пример #3 Пример констант, заданных выражением

class foo const TWO = ONE * 2 ;
const THREE = ONE + self :: TWO ;
const SENTENCE = ‘Значение константы THREE — ‘ . self :: THREE ;
>
?>

Пример #4 Модификаторы видимости констант класса, начиная с PHP 7.1.0

class Foo public const BAR = ‘bar’ ;
private const BAZ = ‘baz’ ;
>
echo Foo :: BAR , PHP_EOL ;
echo Foo :: BAZ , PHP_EOL ;
?>

Результат выполнения данного примера в PHP 7.1:

bar Fatal error: Uncaught Error: Cannot access private const Foo::BAZ in …

Замечание:

Начиная с PHP 7.1.0 для констант класса можно использовать модификаторы области видимости.

User Contributed Notes 19 notes

it’s possible to declare constant in base class, and override it in child, and access to correct value of the const from the static method is possible by ‘get_called_class’ method:
abstract class dbObject
<
const TABLE_NAME = ‘undefined’ ;

public static function GetAll ()
$c = get_called_class ();
return «SELECT * FROM `» . $c :: TABLE_NAME . «`» ;
>
>

class dbPerson extends dbObject
const TABLE_NAME = ‘persons’ ;
>

class dbAdmin extends dbPerson
const TABLE_NAME = ‘admins’ ;
>

echo dbPerson :: GetAll (). «
» ; //output: «SELECT * FROM `persons`»
echo dbAdmin :: GetAll (). «
» ; //output: «SELECT * FROM `admins`»

As of PHP 5.6 you can finally define constant using math expressions, like this one:

class MyTimer const SEC_PER_DAY = 60 * 60 * 24 ;
>

Most people miss the point in declaring constants and confuse then things by trying to declare things like functions or arrays as constants. What happens next is to try things that are more complicated then necessary and sometimes lead to bad coding practices. Let me explain.

A constant is a name for a value (but it’s NOT a variable), that usually will be replaced in the code while it gets COMPILED and NOT at runtime.

So returned values from functions can’t be used, because they will return a value only at runtime.

Arrays can’t be used, because they are data structures that exist at runtime.

One main purpose of declaring a constant is usually using a value in your code, that you can replace easily in one place without looking for all the occurences. Another is, to avoid mistakes.

Think about some examples written by some before me:

1. const MY_ARR = «return array(\»A\», \»B\», \»C\», \»D\»);»;
It was said, this would declare an array that can be used with eval. WRONG! This is just a string as constant, NOT an array. Does it make sense if it would be possible to declare an array as constant? Probably not. Instead declare the values of the array as constants and make an array variable.

2. const magic_quotes = (bool)get_magic_quotes_gpc();
This can’t work, of course. And it doesn’t make sense either. The function already returns the value, there is no purpose in declaring a constant for the same thing.

3. Someone spoke about «dynamic» assignments to constants. What? There are no dynamic assignments to constants, runtime assignments work _only_ with variables. Let’s take the proposed example:

/**
* Constants that deal only with the database
*/
class DbConstant extends aClassConstant <
protected $host = ‘localhost’ ;
protected $user = ‘user’ ;
protected $password = ‘pass’ ;
protected $database = ‘db’ ;
protected $time ;
function __construct () <
$this -> time = time () + 1 ; // dynamic assignment
>
>
?>

Those aren’t constants, those are properties of the class. Something like «this->time = time()» would even totally defy the purpose of a constant. Constants are supposed to be just that, constant values, on every execution. They are not supposed to change every time a script runs or a class is instantiated.

Conclusion: Don’t try to reinvent constants as variables. If constants don’t work, just use variables. Then you don’t need to reinvent methods to achieve things for what is already there.

I think it’s useful if we draw some attention to late static binding here:
class A const MY_CONST = false ;
public function my_const_self () return self :: MY_CONST ;
>
public function my_const_static () return static:: MY_CONST ;
>
>

class B extends A const MY_CONST = true ;
>

$b = new B ();
echo $b -> my_const_self ? ‘yes’ : ‘no’ ; // output: no
echo $b -> my_const_static ? ‘yes’ : ‘no’ ; // output: yes
?>

const can also be used directly in namespaces, a feature never explicitly stated in the documentation.

const BAR = 1 ;
?>

# bar.php
require ‘foo.php’ ;

var_dump ( Foo \ BAR ); // => int(1)
?>

Hi, i would like to point out difference between self::CONST and $this::CONST with extended class.
Let us have class a:

class a <
const CONST_INT = 10 ;

public function getSelf () return self :: CONST_INT ;
>

public function getThis () return $this :: CONST_INT ;
>
>
?>

And class b (which extends a)

class b extends a const CONST_INT = 20 ;

public function getSelf () return parent :: getSelf ();
>

public function getThis () return parent :: getThis ();
>
>
?>

Both classes have same named constant CONST_INT.
When child call method in parent class, there is different output between self and $this usage.

print_r ( $b -> getSelf ()); //10
print_r ( $b -> getThis ()); //20

Источник

Оцените статью