Php extends class const

Php extends class const

For the ‘late static binding’ topic I published a code below, that demonstrates a trick for how to setting variable value in the late class, and print that in the parent (or the parent’s parent, etc.) class.

class cA
/**
* Test property for using direct default value
*/
protected static $item = ‘Foo’ ;

/**
* Test property for using indirect default value
*/
protected static $other = ‘cA’ ;

public static function method ()
print self :: $item . «\r\n» ; // It prints ‘Foo’ on everyway. 🙁
print self :: $other . «\r\n» ; // We just think that, this one prints ‘cA’ only, but. 🙂
>

public static function setOther ( $val )
self :: $other = $val ; // Set a value in this scope.
>
>

class cB extends cA
/**
* Test property with redefined default value
*/
protected static $item = ‘Bar’ ;

public static function setOther ( $val )
self :: $other = $val ;
>
>

class cC extends cA
/**
* Test property with redefined default value
*/
protected static $item = ‘Tango’ ;

public static function method ()
print self :: $item . «\r\n» ; // It prints ‘Foo’ on everyway. 🙁
print self :: $other . «\r\n» ; // We just think that, this one prints ‘cA’ only, but. 🙂
>

/**
* Now we drop redeclaring the setOther() method, use cA with ‘self::’ just for fun.
*/
>

class cD extends cA
/**
* Test property with redefined default value
*/
protected static $item = ‘Foxtrot’ ;

/**
* Now we drop redeclaring all methods to complete this issue.
*/
>

cB :: setOther ( ‘cB’ ); // It’s cB::method()!
cB :: method (); // It’s cA::method()!
cC :: setOther ( ‘cC’ ); // It’s cA::method()!
cC :: method (); // It’s cC::method()!
cD :: setOther ( ‘cD’ ); // It’s cA::method()!
cD :: method (); // It’s cA::method()!

Little static trick to go around php strict standards .
Function caller founds an object from which it was called, so that static method can alter it, replacement for $this in static function but without strict warnings 🙂

error_reporting ( E_ALL + E_STRICT );

function caller () $backtrace = debug_backtrace ();
$object = isset( $backtrace [ 0 ][ ‘object’ ]) ? $backtrace [ 0 ][ ‘object’ ] : null ;
$k = 1 ;

return isset( $backtrace [ $k ][ ‘object’ ]) ? $backtrace [ $k ][ ‘object’ ] : null ;
>

function set_data () b :: set ();
>

static function set () // $this->data = ‘Data from B !’;
// using this in static function throws a warning .
caller ()-> data = ‘Data from B !’ ;
>

$a = new a ();
$a -> set_data ();
echo $a -> data ;

You use ‘self’ to access this class, ‘parent’ — to access parent class, and what will you do to access a parent of the parent? Or to access the very root class of deep class hierarchy? The answer is to use classnames. That’ll work just like ‘parent’. Here’s an example to explain what I mean. Following code

class A
protected $x = ‘A’ ;
public function f ()
return ‘[‘ . $this -> x . ‘]’ ;
>
>

class B extends A
protected $x = ‘B’ ;
public function f ()
return ‘ x . ‘>’ ;
>
>

class C extends B
protected $x = ‘C’ ;
public function f ()
return ‘(‘ . $this -> x . ‘)’ . parent :: f (). B :: f (). A :: f ();
>
>

$a = new A ();
$b = new B ();
$c = new C ();

Nice trick with scope resolution
class A
public function TestFunc ()
return $this -> test ;
>
>

public function __construct ()
$this -> test = «Nice trick» ;
>

public function GetTest ()
return A :: TestFunc ();
>
>

$b = new B ;
echo $b -> GetTest ();
?>

will output

This is a solution for those that still need to write code compatible with php 4 but would like to use the flexibility of static variables. PHP 4 does not support static variables within the class scope but it does support them within the scope of class methods. The following is a bit of a workaround to store data in static mode in php 4.

Note: This code also works in PHP 5.

The tricky part is when using when arrays you have to do a bit of fancy coding to get or set individual elements in the array. The example code below should show you the basics of it though.

class StaticSample
//Copyright Michael White (www.crestidg.com) 2007
//You may use and modify this code but please keep this short copyright notice in tact.
//If you modify the code you may comment the changes you make and append your own copyright
//notice to mine. This code is not to be redistributed individually for sale but please use it as part
//of your projects and applications — free or non-free.

//Static workaround for php4 — even works with arrays — the trick is accessing the arrays.
//I used the format s_varname for my methods that employ this workaround. That keeps it
//similar to working with actual variables as much as possible.
//The s_ prefix immediately identifies it as a static variable workaround method while
//I’m looking thorugh my code.
function & s_foo ( $value = null , $remove = null )
static $s_var ; //Declare the static variable. The name here doesn’t matter — only the name of the method matters.

if( $remove )
if( is_array ( $value ))
if( is_array ( $s_var ))
foreach( $value as $key => $data )
unset( $s_var [ $key ]);
>
>
>
else
//You can’t just use unset() here because the static state of the variable will bring back the value next time you call the method.
$s_var = null ;
unset( $s_var );
>
//Make sure that you don’t set the value over again.
$value = null ;
>
if( $value )
if( is_array ( $value ))
if( is_array ( $s_var ))
//$s_var = array_merge($s_var, $value); //Doesn’t overwrite values. This adds them — a property of the array_merge() function.
foreach( $value as $key => $data )
$s_var [ $key ] = $data ; //Overwrites values.
>
>
else
$s_var = $value ;
>
>
else
$s_var = $value ;
>
>

echo «Working with non-array values.
» ;
echo «Before Setting: » . StaticSample :: s_foo ();
echo «
» ;
echo «While Setting: » . StaticSample :: s_foo ( «VALUE HERE» );
echo «
» ;
echo «After Setting: » . StaticSample :: s_foo ();
echo «
» ;
echo «While Removing: » . StaticSample :: s_foo ( null , 1 );
echo «
» ;
echo «After Removing: » . StaticSample :: s_foo ();
echo «


» ;
echo «Working with array values
» ;
$array = array( 0 => «cat» , 1 => «dog» , 2 => «monkey» );
echo «Set an array value: » ;
print_r ( StaticSample :: s_foo ( $array ));
echo «
» ;

//Here you need to get all the values in the array then sort through or choose the one(s) you want.
$all_elements = StaticSample :: s_foo ();
$middle_element = $all_elements [ 1 ];
echo «The middle element: » . $middle_element ;
echo «
» ;

$changed_array = array( 1 => «big dog» , 3 => «bat» , «bird» => «flamingo» );
echo «Changing the value: » ;
print_r ( StaticSample :: s_foo ( $changed_array ));
echo «
» ;

//All you have to do here is create an array with the keys you want to erase in it.
//If you want to erase all keys then don’t pass any array to the method.
$element_to_erase = array( 3 => null );
echo «Erasing the fourth element: » ;
$elements_left = StaticSample :: s_foo ( $element_to_erase , 1 );
print_r ( $elements_left );
echo «
» ;
echo «Enjoy!» ;

  • Классы и объекты
    • Введение
    • Основы
    • Свойства
    • Константы классов
    • Автоматическая загрузка классов
    • Конструкторы и деструкторы
    • Область видимости
    • Наследование
    • Оператор разрешения области видимости (::)
    • Ключевое слово static
    • Абстрактные классы
    • Интерфейсы объектов
    • Трейты
    • Анонимные классы
    • Перегрузка
    • Итераторы объектов
    • Магические методы
    • Ключевое слово final
    • Клонирование объектов
    • Сравнение объектов
    • Позднее статическое связывание
    • Объекты и ссылки
    • Сериализация объектов
    • Ковариантность и контравариантность
    • Журнал изменений ООП

    Источник

    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 .

    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  // This is legal since Test::A is private public const string A = 'a'; // This is legal since int is a subtype of mixed public const int B = 0; // This is illegal since mixed is a supertype of int public const mixed C = 0; // This is legal since Foo&Stringable is more restrictive than Foo 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 array H = 'a'; public const int

    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.

    Источник

    Читайте также:  Javascript for adobe indesign
Оцените статью