web-dev-qa-db-fra.com

PHP traits - définition de constantes génériques

Quelle est la meilleure façon de définir des constantes qui peuvent être utilisées par un certain nombre de classes dans un espace de noms? J'essaie d'éviter trop d'héritage, donc l'extension des classes de base n'est pas une solution idéale, et j'ai du mal à trouver une bonne solution en utilisant des traits. Est-ce possible de quelque manière que ce soit en PHP 5.4 ou faut-il adopter une approche différente?

J'ai la situation suivante:

trait Base
{
    // Generic functions
}

class A 
{
    use Base;
}

class B 
{
    use Base;
}

Le problème est qu'il n'est pas possible de définir des constantes dans les traits PHP. Idéalement, je voudrais quelque chose comme ceci:

trait Base
{
    const SOME_CONST = 'someconst';
    const SOME_OTHER_CONST = 'someotherconst';

    // Generic functions
}

Ensuite, ceux-ci pourraient être accessibles via la classe qui applique le trait:

echo A::SOME_CONST;
echo B::SOME_OTHER_CONST;

Mais en raison des limites des traits, cela n'est pas possible. Des idées?

50
Tom Jowitt

J'ai fini par utiliser suggestion de la secte de l'utilisateur des interfaces car cela semble être la façon la moins problématique de gérer cela. L'utilisation d'une interface pour stocker des constantes plutôt que des contrats d'API a une mauvaise odeur, alors peut-être que ce problème concerne plus la conception OO que l'implémentation des traits).

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;
}

Ce qui permet:

A::SOME_CONST;
B::SOME_CONST;
70
Tom Jowitt

Vous pouvez également utiliser des variables statiques. Ils peuvent être utilisés dans la classe ou le trait lui-même. - Fonctionne bien pour moi en remplacement de const.

trait myTrait {
    static $someVarA = "my specific content";
    static $someVarB = "my second specific content";
}

class myCustomClass {
    use myTrait;

    public function hello()
    {
        return self::$someVarA;
    }
}
24
Michael

Pour limiter la portée de vos constantes, vous pouvez les définir dans un espace de noms:

namespace Test;

const Foo = 123;

// generic functions or classes

echo Foo;
echo namespace\Foo;

Un inconvénient de cette approche est que le chargement automatique ne fonctionnera pas pour les constantes, du moins pas pour 5.4; la manière typique de contourner cela est d'envelopper ces constantes dans une classe statique, c'est-à-dire:

namespace Test;

class Bar
{
    const Foo = 123;
}
9
Ja͢ck

Pas bon, mais peut-être ...

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();
4
Jekis

Il existe une façon un peu hackée de le faire, en définissant une constante, puis en renvoyant cette constante avec vos fonctions de trait:

define ('myConst','this is a constant');

trait Base {
  public function returnConst() {
    return myConst;
  }
}

class myClass {
  use Base;
}

$o = new myClass();
echo $o->returnConst();
1

Quelque chose d'autre à considérer est de savoir si vous pouvez utiliser une classe abstraite à la place, puis hériter.

abstract class Base
{
    const A = 1;
    const B = 2;
}

class Class1 extends Base {}
class Class2 extends Base {}

echo Class1::A;
echo Class2::B;

Bien sûr, une partie de la raison des traits est de remplacer les arbres d'héritage complexes par la composition. Dépend de la situation.

0
Osan