Force declaration of properties

9

I'm implementing a filtering feature in some classes of my application through traits .

The function of trait will use 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 trait that the property be defined in the class. I thought I'd implement this functionality from inheritance, but I'd lose the flexibility of using trait in other parts of my application.

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

My problem is not to declare the property in trait , even that was my first attempt, but if the class has the same property, a collision error occurs with the properties name.

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: EstoqueMeta and FilterTrait define 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

    
asked by anonymous 29.08.2014 / 21:55

2 answers

3

I believe that it is not possible to do what you want, properties are at most inherited as far as I know. But you can solve this without having to define a property, you can leave a method for your class to implement, 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'));
    
30.08.2014 / 02:41
0

So far as to force the property to be set, I've implemented a method on trait that triggers a Exception if the property is not set.

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 if trait has more methods that need properties out of its scope, you must call the checkProperties() method on all methods.

    
02.09.2014 / 13:28