Как инициализировать свойства типа Объект в trait'ах PHP или существует ли возможность регистрации нескольких __construct методов в очередь?

Пытался задать вопрос на stackoverflow, но, видимо, из-за корявого английского меня там не поняли. Мне нужно инициализировать свойство трейта как экземпляр соседнего класса.
trait FilterTrait {
    protected $_filter = new Filter(); // Нельзя использовать как дефолтное значение

    public function __construct () { // Перезапишется в используемом классе
        $this->_filter = new Filter();
    }

    public function SetFilter ($arFilter) {
        $this->_filter->Set($arFilter);
    }

    public function CleanFilter () {
        $this->_filter->CLean();
    }

    public function GetFilter () {
        return $this->_filter->Get();
    }
    ...
}


Не хочу, чтобы дочерний класс помогал в работе используемого трейта, и вообще знал что-то об его устройстве, вот так:
class Select extends Query {
    use TablesListTrait,
        FieldsListTrait,
        FilterTrait,
        HavingTrait,
        SortTrait,
        LimitTrait,
        GroupTrait;

    function __construct () {
        $this->_tablesList = new TablesList();
        $this->_fieldsList = new FieldsList();
        $this->_filter = new Filter();
        ...
    }
    ...
}


И инициализировать при каждом вызове метода тоже не хочу
trait FilterTrait {
    protected $_filter;

    public function InitializeFilter () {
        if (is_null($this->_filter)) {
            $this->_filter = new Filter();
        }
    }

    public function SetFilter ($arFilter) {
        $this->InitializeFilter();
        $this->_filter->Set($arFilter);
    }

    public function CleanFilter () {
        $this->InitializeFilter();
        $this->_filter->CLean();
    }

    public function GetFilter () {
        $this->InitializeFilter();
        return $this->_filter->Get();
    }
}

Можно, конечно, замутить перезагрузку методов, но это не сильно лучше.

Нашел информацию о том, что в версии 5.6 вот такое написание поддерживается
class Foo {
    protected $bar = new Baz();
}

не проверял, но все-таки большинство хостингов на данный момент стоят на 5.3 - 5.4, и использовать эти фишки пока сложно. К тому же хочу еще реализовать регистрацию мнемоник для вызова методов трейта из параметров, передающихся в дочерние классы. Если бы существовал какой-нибудь магический метод, регистрирующий несколько __construct функций, мне бы это помогло:
trait Actions {
    protected $_arActions = array();

    public function RegisterActions ($arActions) {
        $this->_arActions = array_merge($this->_arActions, $arActions);
    }

    public function ResetParameters ($arParameters) {
        foreach ($arParameters as $mnemonic => $actionParameters) {
            if (isset($this->_arActions[$mnemonic])) {
                $action = $this->_arActions[$mnemonic];
                $this->$action($actionParameters);
            }
        }
    }
}

trait FilterTrait {
    use Actions;
    
    public function __onUse () {
        $arActions = array(
            "filter" => "SetFilter"
        );
        $this->RegisterActions($arActions);
    }
    
    public function SetFilter ($arFilter) {...}
}

class Select extends Query {
    use TablesListTrait,
        FieldsListTrait,
        FilterTrait,
        HavingTrait,
        SortTrait,
        LimitTrait,
        GroupTrait;
    
    public function __construct ($arParams) {
        $this->ResetParameters($arParams);
    }
}

...
$arSelectParams = array(
    "table" => "products",
    "fields" => array(
        "id",
        "name",
        "price"
    ),
    "filter" => array(
        "id" => 5,
        "<=price" => 1000
    ),
    "sort" => array(
        "price" => "asc"
    )
);
$query = new Select($arSelectParams);


Есть какой-нибудь вариант сделать что-то подобное сейчас или, если нет, ожидается ли концепция подобного в будущем, где-нибудь в седьмой версии?
  • Вопрос задан
  • 259 просмотров
Пригласить эксперта
Ответы на вопрос 1
index0h
@index0h
PHP, Golang. https://github.com/index0h
Концепция с дефолтным объектом - это хреновая затея. Подключение к БД вы например как в свойстве класса сделаете (не объекта)?

Трейты - это довольно опасная штука, которая расширяет функционал ваших классОВ. Вы же хотите, что бы она жила своей жизнью в контексте каждого класса, это не правильно, вам тут не Golang)).

На счет вашего примера работы с БД: вам трейты тут не нужны, от слова "совсем")). Расширьте ваш Query методами, что вы хотите пихать в трейты. Класс Select вам тоже не нужен, добавьте его функционал как метод в Query. Если я правильно понимаю Query - это объект с состоянием, который в результате должен суметь создать SQL код, дык добавьте в него еще метод getSQL().

Обратите внимание на защиту от SQL-инъекций. Что будет, если вызвать ваш Select так:

<?php

$query = new Select(
    [
        'table'  => "1;DROP TABLE products;",
        'fields' => [],
    ]
);


Вообще говоря: если цель понаучаться - дерзайте, если таки дело делаете - используйте Doctrine2, не стоит терять время для поделку, которая 99.99% будет хуже существующих аналогов.

Очень вам рекомендую, почитайте PSR-2

Чуть не забыл:

Как инициализировать свойства типа Объект в trait'ах PHP?

В классе, который подключает трейт, на прямую, или через вызов метода из трейте.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы