Force property declaration

Asked

Viewed 274 times

9

I am implementing a filter functionality in some classes of my application through traits.

The function of trait will refer to class variables through some properties defined in the class:

<?php

trait FilterTrait {    
    public function scopeApplyFilters($filters) {
        foreach (self::$allowedFilters as $filter) {
             // Executa método
        }
     }
}

class EstoqueMeta extends Eloquent {
    use FilterTrait;
    static public $allowedFilters = array('foo','bar');
}

I would like to force from the trait the property is defined in the class. I thought to implement this functionality from heritage, but I would lose the flexibility of using the trait in other parts of my application.

Is there any way to "force" the declaration of the properties from the trait? If not, there is some alternative without inheritance?


My problem is not declaring property on trait, this was my first attempt, but if the class has the same property, there will be a collision error with the name of the properties.

trait FilterTrait {    
    public $allowedFilters = array();    
    public function scopeApplyFilters($filters) {
        foreach (self::$allowedFilters as $filter) {
             // Executa método
        }
     }
}

class EstoqueMeta {
    use FilterTrait;    
    public $allowedFilters = array('foo', 'bar');
}

Fatal error: Stockpile and Filtertrait defines the same Property ($allowedFilters) in the Composition of Estoquemeta. However, the Definition differs and is considered incompatible. Class was composed in [...][...] on line 23

Example

  • 1

    Declare the property on trait does not solve? I do not know the implementation of trait in PHP, why would you lose the ability to use in other classes?

  • @bigown already tried, but php does not allow.

  • 2

    The property needs to be Static? you can declare properties in Trait without any problem!

  • 5

    http://meta.pt.stackoverflow.com/questions/1901/essa-pergunta-pode-ser-considerada-uma-pergunta-camale%C3%A3o

2 answers

3


I believe that it is not possible to do what you want, properties are inherited at most as far as I know. But it is possible to solve this without the need to define a property, you can leave a method for your implement class, you can use an interface or leave an abstract method in your trait to do this

Example:

    trait FilterTrait
    {

        abstract public function getAllowedFilters();

        public function scopeApplyFilters(array $filters)
        {
            foreach ($filters as $filter) {
                if (false === \in_array($filter, $this->getAllowedFilters())) {

                }
            }
        }

    }

    class EstoqueMeta
    {

        use FilterTrait;

        public function getAllowedFilters()
        {
            return array('foo', 'bar');
        }

    }

    $estoque = new EstoqueMeta();

    $estoque->scopeApplyFilters(array('foo'));

0

So far to force the property to be defined, I have implemented a method in the trait that fires a Exception if the property is not defined.

trait FilterTrait {    
    public $allowedFilters = array();    
    public function scopeApplyFilters($filters) {

        $this->checkProperties();

        foreach (self::$allowedFilters as $filter) {
             // Executa método
        }
    }

    private function checkProperties(){
        if (!isset(self::$allowedFilters)){
            throw new Exception('Required properties are not defined.');
        }
    }

}

// Classe
class EstoqueMeta {
    use FilterTrait;          
}

$model = new EstoqueMeta();

// Exception: Required properties are not defined.
$model->scopeApplyFilters(['foo' => 123, 'bar' => 456]); 

The disadvantage of this method is that trait has more methods that need properties outside its scope, it is necessary to call the method checkProperties() in all methods.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.