2

Base classes (usually abstract ones) can have methods which can be tuned with overriding constants in child classes. Those constants can also have default values.

example:

abstract class BaseClass{
    const NAME = '<default name>';

    public function sayHello(){
        printf("Hello! My name is %s\n", static::NAME);
    }
}

// will use default constant value
class SomeClass extends BaseClass{}

// constant value is overridden
class OtherClass extends BaseClass{
    const NAME = 'Stephen Hawking';
}

(new SomeClass())->sayHello(); // Hello! My name is <default name>
(new OtherClass())->sayHello(); // Hello! My name is Stephen Hawking

But if I replace abstract class with trait I get

PHP Fatal error:  Traits cannot have constants in /mnt/tmpfs/1.php on line 4

So is it possible to use them in traits?

Update:

This question header looks similar to this but they are completely different and somewhat opposite.

Other question is about defining constant in a trait and adding it to multiple classes. So the same constant value is added to different classes.

My question is about using constant in a method and overriding it in different classes. So different classes have different constant values which are used to configure a method.

quant2016
  • 447
  • 4
  • 13
  • Rust equivalent of feature which https://stackoverflow.com/questions/24357985/php-traits-defining-generic-constants tries to implement is here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e04415ec515308dfd193d69a3f423ca2 rust equivalent to I try to implement is here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=be07e58154296b54b2cdc63c44d4f47a – quant2016 Feb 14 '23 at 18:52

1 Answers1

0

Someone suggested to use static properties instead, but it doesn't work because of

PHP Fatal error:  OtherClass and SayTrait define the same property ($name) in the composition of OtherClass. However, the definition differs and is considered incompatible. Class was composed in /mnt/tmpfs/1.php on line 19

So possible workaroud is to use trait in parent class then extend target class from it.

trait SayTrait {
    public static $name = '<default name>';

    public function sayHello(){
        printf("Hello! My name is %s\n", static::$name);
    }
}


class SomeClass{
    use SayTrait;
}

// added as workaround.
abstract class ParentClass{
    use SayTrait;
}
// I have to move using trait to parent class to avoid Fatal Error
class OtherClass extends ParentClass {
    public static $name = 'Stephen Hawking';
}

(new SomeClass())->sayHello();
(new OtherClass())->sayHello();

Another solution is to use value hardcoded in method itself if class constant is not defined. Unfortunately, null coalescing operator (??) doesn't work with constants so I have to use defined + ternary operator(thanks to https://stackoverflow.com/a/50974262)

trait SayTrait {

    public function sayHello(){
        printf("Hello! My name is %s\n", defined('static::NAME')? static::NAME : '<default name>');
    }

}

class SomeClass{
    use SayTrait;
}

class OtherClass {
    use SayTrait;
    const NAME = 'Stephen Hawking';
}

(new SomeClass())->sayHello();
(new OtherClass())->sayHello();

quant2016
  • 447
  • 4
  • 13