Как инициализировать свойства типа Объект в 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);


Есть какой-нибудь вариант сделать что-то подобное сейчас или, если нет, ожидается ли концепция подобного в будущем, где-нибудь в седьмой версии?
  • Вопрос задан
  • 235 просмотров
Пригласить эксперта
Ответы на вопрос 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?

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

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

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
от 300 000 до 500 000 ₽
07 мая 2024, в 18:23
20000 руб./за проект
07 мая 2024, в 18:09
2000 руб./за проект
07 мая 2024, в 17:40
300 руб./за проект