затраты на лямбду равны затратам на работу с именем класса из строки

grigori

( ͡° ͜ʖ ͡°)
Команда форума
я всегда думал, что использование ламбды добавляет некоторый незначительный overhead,
но оказалось, что затраты в точности равны работе с именами классов из строковых констант

тест:

PHP:
Class A{}

$x = [];
for ($i=0;$i<10;++$i){
	$x[$i] = function(){
		return new A();
	};
	$x[$i]();
};


echo memory_get_usage(true),' ';
# time for i in {1..100}; do php test.php; done;
262144
user 0m0.698s
PHP:
Class A{}

$x = [];
for ($i=0;$i<10;++$i){
	$x[$i] = array('class'=>'A');
	new $x[$i]['class'];
};
echo memory_get_usage(true),' ';
# time for i in {1..100}; do php test.php; done;
262144
user 0m0.695s
Вообще, это мысль строить конфиги, DI-контейнеры и определять компоненты приложений не массивами со строковыми константами и плейсхолдерами, не соглашениями с макро-языком для имен параметров, как в symfony, а простым php-кодом в лямбдах:

PHP:
 'myComponent'=>function(CApplication $App){
  return Foo::factory('paramN');
 }
Классы, которые использованы в лямбде, загружаются только при исполнении лямбды, а не при инициализации.

Это позволит, например, в IDE показывать места использования классов в конфигах,
позволит в конфиге yii использовать алиасы, классы и зависимые компоненты, доступные только после инициализации приложения.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Такое есть: http://pimple.sensiolabs.org/

Но на практике неудобно, если зависимостей много.

Я как-то краем уха слышал, что хотят сделать какой-то стандарт для описания зависимостей в PHP через конфиги типа YAML, тогда и IDE научится видеть. Но как по мне это не такая уж киллер-фича.
 

Redjik

Джедай-мастер
Вурдалак
я краем уха слышал от флоппика в какой-то другой теме (там был линк на пруф, но сейчас не найду), что как раз jetBrains хотят ввести
описания зависимостей в PHP через конфиги типа YAML
а вот про стандарт - не попадалось
 

keltanas

marty cats
позволит в конфиге yii использовать алиасы, классы и зависимые компоненты, доступные только после инициализации приложения.
Ох уж эти yii-программисты... А я думал, что этот подход противоречит вашей религии... ;)

Если в контейнере Symfony не нравится использовать yaml или xml, всегда можно написать просто и понятно на php:
PHP:
$container->setParameter('mailer.transport', 'sendmail');
$container
    ->register('mailer', 'Mailer')
    ->addArgument('%mailer.transport%');
// Hint: Там в примерах кода 3 вкладочки, а не одна.
Все остальное, что ты хочешь нахардкодить с помощью лямд, уже реализовано под капотом контейнера и, например, все равно не решает проблемы зависимостей одного сервиса от другого.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
мне не нравится идея интерпретируемого макро-языка для описания связей компонентов приложения поверх PHP
я хочу писать на PHP, а не на Symfony-, Yii- или Laravel-диалекте, как заставляют меня их авторы

Pimple - да, это оно, только не хватает сахара, чтобы можно было:
PHP:
class MyPimple extends Pimple{
/*@var iSession $session */
/*@var string $session_save_path */
}
$config = [
'session_save_path'=>'application.runtime.sessions',
'session' => function (MyPimple $c) {
    return new MySession($c->session_save_path);
};]
$container = new MyPimple($config);

$container->session->store($key,$val);
кстати, он сам может определить типы данных из
/*@var iSession $session */
/*@var string $session_save_path */
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Pimple - да, это оно, только не хватает сахара, чтобы можно было:
PHP:
class MyPimple extends Pimple{
/*@var iSession $session */
/*@var string $session_save_path */
}
$config = [
'session_save_path'=>'application.runtime.sessions',
'session' => function (MyPimple $c) {
    return new MySession($c->session_save_path);
};]
$container = new MyPimple($config);

$container->session->store($key,$val);
кстати, он сам может определить типы данных из
/*@var iSession $session */
/*@var string $session_save_path */
Так ты и не должен такого хотеть, у тебя где-то там в контроллере будет
PHP:
class Controller
{
	public function __construct(iSession $session);
}
и угадывать ничего не нужно.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
а контроллеры тут ни при чем, я говорю в первую очередь о сервисах, которые вызываются через контейнер в произвольном месте из контроллера или из модели;
например, у меня это может быть объект с маппингом внешней rpc-службы, его не надо inject-ить в контроллер, к нему надо обращаться через контейнер, например:
$Customer = Yii::app()->rpc->loadCustomer($customer_id);
Yii::app() - контейнер, rpc - сервис, который мне надо инициализировать через конфиг,
и я предлагаю это делать через лямбды вместо магических констант ->register('rpc', 'RPC')->addArgument('%rpc.transport%');
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Контроллеры точно так же могут быть сервисами. Твой контроллер зависит от rpc, значит в него точно так же можно инжектить эту зависимость. То есть тут выбор: либо тебе каждый раз дописывать @property:
PHP:
/**
 * @property iSession $session
 */
class MyContainer extends Pimple {
}
либо дописать зависимости контроллера в конфиге и инжектить по-нормальному.

Ну это если хочется автокомплита.
 

WMix

герр M:)ller
Партнер клуба
grigori
в любых классах и так описываются конструкторы с зависимостями типы данных которых могут быть даже интерфейсами.
при конфигурации di уже создаются конкретные инстанции зависимости.
PHP:
interface A{}
class B implements A{}

class C{
   public function __construct(A $b){}
}

$container['c'] = function () {
    return new C( new B );
};
или я вопроса не понимаю?
 

Absinthe

жожо
Так ты и не должен такого хотеть, у тебя где-то там в контроллере будет
и угадывать ничего не нужно.
Только у меня одного в проектах есть несколько классов с одинаковыми интерфейсами?
Без описания определений ничего не получить в таких случаях.
 

Вурдалак

Продвинутый новичок

hell0w0rd

Продвинутый новичок
А зачем инжектить в класс контроллера, а не метод, как это делается в symfony/silex? Только если я не ошибаюсь в symfony можно еще этот подход и закешировать.
То есть пишите
PHP:
public function blaBlaAction(Request $request, Connection $connect, $id, $name)
{
}
И controllerResolver сам разруливать что и куда инжектить. В принципе это дело можно даже не кешировать, рефлексия медленная, но не для вызова одной функции
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Контроллеры точно так же могут быть сервисами.
Нет, контроллеры - это классы, которые обрабатывают действия пользователя. Они не могут быть сервисами. Сервисы занимаются обработкой данных, это модель, и только модель. Controller as a Service в symfony - это другое. Давайте говорить на общем языке - gof/Fowler.

Твой контроллер зависит от rpc, значит в него точно так же можно инжектить эту зависимость.
можно, но я сейчас ориентируюсь на архитектуру yii/symfony, где в action передаются параметры ввода.
Инъекция зависимостей через параметр - вероятно, твой стиль кодинга, но я обсуждаю не его, а стандартный подход - прямой вызов сервисов из контейнера.

но я писал про синтаксис конфига, а не про виды инъекций
 

Absinthe

жожо
Вурдалак первую часть проглядел в твоем сообщении, обратил внимание только на вторую и подумал, что там код в стиле Laravel контейнера.
Контроллеры как сервисы и юзаю.

Нет, контроллеры - это классы, которые обрабатывают действия пользователя. Они не могут быть сервисами.
Приехали :)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Absinthe хорошо, вы активно юзаете контроллеры как сервисы и инъектите зависимости прямо в них. Я не хочу это обсуждать, я просто использую термины в их изначальном значении.
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
grigori
в любых классах и так описываются конструкторы с зависимостями типы данных которых могут быть даже интерфейсами.
при конфигурации di уже создаются конкретные инстанции зависимости.
или я вопроса не понимаю?
вопрос в синтаксисе конфига, а не в DI как таковом
 

hell0w0rd

Продвинутый новичок
А интересно вот такое есть в каком-нибудь dic-е?
PHP:
class IndexController
{
    use ClosureInjectTrait;

    /**
     * @ var Resuest
     */
    private $request = 'kernel.request';

    /**
     * @ var MySuperService
     */
    private $mySuperServise = 'my_super_service';
}


// Где-то где создается контроллер и инжектятся зависимости
$c = new $controller;

if($c instanceof ClosureInjectTrait) {
    \Closure::bind(function () use($dic) {
        foreach (get_object_vars($this) as $var => $value) {
            if (is_string($value)) {
                $this->$var = $dic->get($value);
            }
        }
    }, $c, $controller);
}
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Что есть сервисы и могут ли ими быть контроллеры - это вообще не имеет значения и к теме не имеет никакого отношения. Вы хотите обсуждать зависимости, контроллеры и методы инъекций - хорошо, но это другая тема. Простите за frustration, я пишу соображения лишь по поводу синтаксиса, не по архитектуре и видам сервисов в разных фреймворках вообще.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
hell0w0rd, ну это ж тоже самое, что через аннотации. Это неявная зависимость от контейнера.
 
Сверху