What is the best way to define constants that may be used by a number of classes within a namespace? I'm trying to avoid too much inheritance so extending base classes is not an ideal solution and I'm struggling to find a good solution using traits. Is this in any way possible in PHP 5.4 or should a different approach be taken?
I have the following situation:
trait Base
{
// generic functions
}
class A
{
use Base;
}
class B
{
use Base;
}
The problem is that it is not possible to define constants in PHP traits. Ideally what I would want is something like the following:
trait Base
{
const SOME_CONST = 'someconst';
const SOME_OTHER_CONST = 'someotherconst';
// generic functions
}
Then these could be accessed though the class that applies the trait:
echo A::SOME_CONST;
echo B::SOME_OTHER_CONST;
But due to the limitations of traits this isn't possible. Any ideas? Thanks.
I ended up using @sectus suggestion of interfaces as it feels like the least-problematic way of handling this. Using an interface to store constants rather than API contracts has a bad smell about it though so maybe this issue is more about OO design than trait implementation. I'm still not perfectly happy with this solution so won't accept the answer for a while in case someone has better suggestion.
interface Definition
{
const SOME_CONST = 'someconst';
const SOME_OTHER_CONST = 'someotherconst';
}
trait Base
{
// generic functions
}
class A implements Definition
{
use Base;
}
class B implements Definition
{
use Base;
}
Which allows for:
A::SOME_CONST;
B::SOME_CONST;
You could also use static variables. They can be used in the class or the trait itself. - Works fine for me as a replacement for const.
trait myTrait {
static $someVarA = "my specific content";
static $someVarB = "my second specific content";
}
class myCustomClass {
use myTrait;
public function hello()
{
return self::$someVarA;
}
}
To limit the scope of your constants, you can define them inside a namespace:
namespace Test;
const Foo = 123;
// generic functions or classes
echo Foo;
echo namespace\Foo;
A downside of this approach is that autoloading won't work for constants, at least not for 5.4; the typical way around this is to wrap those constants in a static class, i.e.:
namespace Test;
class Bar
{
const Foo = 123;
}
Not a good one, but maybe...
trait Base
{
public static function SOME_CONST()
{
return 'value1';
}
public static function SOME_OTHER_CONST()
{
return 'value2';
}
// generic functions
}
class A
{
use Base;
}
class B
{
use Base;
}
echo A::SOME_CONST();
echo B::SOME_OTHER_CONST();
there is a bit hackish way of doing this, by defining a constant, then returning this constant with your trait functions:
define ('myConst','this is a constant');
trait Base {
public function returnConst() {
return myConst;
}
}
class myClass {
use Base;
}
$o = new myClass();
echo $o->returnConst();
Something else to consider is whether or not you can use an abstract class instead, and then inherit.
abstract class Base
{
const A = 1;
const B = 2;
}
class Class1 extends Base {}
class Class2 extends Base {}
echo Class1::A;
echo Class2::B;
Of course, part of the reason for traits is replace complex inheritance trees with composition. Depends on the situation.