Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.137.220.120] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Представьте себе функцию, которая принимает значение «по ссылке» и способна как-то влиять на это значение.
Например представьте себе такую надуманную функцию, как increment_this_one. Эта функция — надуманный пример — увеличивает значение, ссылка на которое передана, на единицу. function increment_this_one(&$foo) { $foo++; } Замечательно, теперь мы можем сделать что-то подобное: $a = 1; $b = 10; $c = 77; increment_this_one($a); increment_this_one($b); increment_this_one($c); var_dump($a, $b, $c); // Вывод: 2 11 78 Замечательно. Но вам этого мало. Теперь вы хотите воспользоваться возможностью иметь функцию с переменным числом аргументов. Такое возможно. Новая функция — increment_them_all, и её суть в том, что она увеличивает все значения, ссылки на которые были переданы. Разумеется, в реальности у меня совершенно иная функция, но для простоты ведения топика будем использовать именно этот надуманный пример. function increment_them_all() { /* Вся магия здесь */ } $a = 111; $b = 222; $c = 333; increment_them_all(&$a, &$b, &$c); // Ожидаемый результат: // $a => 112 // $b => 223 // $c => 334 Проблема в том, что func_get_args (на которой зиждется весь трюк с переменным числом параметров) возвращает массив, каждый элемент которого является копией переданного значения, а не ссылкой на переданное значение. При такой реализации imcrement_them_all: function increment_them_all() { $args = func_get_args(); for($i = 0; $i < count($args); $i++) $args[$i]++; } $a = 1; $b = 2; $c = 3; increment_them_all(&$a, &$b, &$c); var_dump($a, $b, $c); Мы получаем совсем не то, что ожидаем. Поскольку массив $args содержит не ссылки на значения «1», «2» и «3», а копии этих значений, то и оператор «++» применяется к копиям, а оригинальные значения остаются нетронутыми. (Пожалуйста, если вы один из тех людей, кто не до конца понимает концепцию ссылок в PHP, воздержитесь от того, чтобы писать здесь свои соображения, основанные на неправильном понимании сути вещей) Я считаю, что это косячная реализация функции func_get_args. Но встаёт другой вопрос: как же всё-таки (чёрт возьми!) реализовать любую функцию, в отношении которой справедливо оба утверждения: 1) Функция принимает переменное число аргументов 2) Функция принимает их по ссылке и может влиять на них, в частности, возвращать что-то через них (как fscanf). Я придумал workaround для этой проблемы. Он позволяет функциям с переменным числом аргументов провести над аргументами какую-то (возможно достаточно сложную) обработку значений и вернуть новые значения «через ссылку»: С одной стороны, такой workaround — это хоть что-то (по сравнению с ничем). С другой стороны — он чудовищно грязный, и не нравится мне. Суть workaround-а: function very_complicated_vararg_func( // da --- dummy argument &$da0=NULL,&$da1=NULL,&$da2=NULL,&$da3=NULL,&$da4=NULL,&$da5=NULL,&$da6=NULL,&$da7=NULL, &$da8=NULL,&$da9=NULL,&$da10=NULL,&$da11=NULL,&$da12=NULL,&$da13=NULL,&$da14=NULL,&$da15=NULL) { $args = func_get_args(); /* Очень сложна обработка массива аргументов */ /* Чудовищно сложная обработка массива аргументов */ /* Невероятно сложная обработка массива аргументов */ /* Всё, закончили с обработкой массива аргументов... */ // // А теперь исправляем дефективную природу func_get_args: // for($i = 0; $i < count($args); $i++) { $dummy_arg_name = "da$i"; $$dummy_arg_name = $args[$i]; } } Вот теперь функция умеет не только принимать переменное число аргументов, но и «возвращать» новые значения через ссылки. Но во-первых, выглядит это вырвиглазно. И макс. количество аргументов ограниченно кол-вом dummy-argument-ов. Есть идеи получше? Скрытый текст Я предполагаю, что вопросов, какая реальная задача — не избежать. Реальная задача такая: в рамках реализации паттерна Publisher←→Subscribers реализовать функцию Notify, которая принимает заранее неизвестный набор параметров, и должна вызвать NotificationHandler у каждого из подписавшихся объектов, передав в NotificationHandler весь тот заранее неизвестный набор параметров, который ей (то есть функции Notify) передали. |
Сообщ.
#2
,
|
|
|
Ну вот и поговорили
По сути дела по моему проще уже массив в функцию передавать... |
Сообщ.
#3
,
|
|
|
Цитата fatalist @ По сути дела по моему проще уже массив в функцию передавать... Нет, не пойдёт. Уж лучше такой workaround, малозаметный, чем каждый раз писать $this->SomeEvent->NotifySubscribers(array(пара-тройка-параметров)); вместо $this->SomeEvent->NotifySubscribers(пара-тройка-параметров); |
Сообщ.
#4
,
|
|
|
Цитата Хакер @ этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4... &$a, &$b, &$c |
Сообщ.
#5
,
|
|
|
Цитата negram @ Цитата (Хакер @ Сегодня, 19:40) &$a, &$b, &$c этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4... ну так ясен ) передачу параметров по ссылке через амерсенд отменили. Цитата Хакер @ Нет, не пойдёт. Уж лучше такой workaround, малозаметный, чем каждый раз писать загляни в лучшые фреймы. там именно передача массивов преобладает. |
Сообщ.
#6
,
|
|
|
Просто так, ради фана: http://www.php.net/manual/ru/function.runk...on-redefine.php
Добавлено только оно в пекле валяется Добавлено Цитата negram @ этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4... работаэ о0 Добавлено у меня. С полными варнингами. Никаких эксепшонов |
Сообщ.
#7
,
|
|
|
Цитата Serafim @ у меня. С полными варнингами. Никаких эксепшонов E_DEPRECATED - и есть ворнинг |
Сообщ.
#8
,
|
|
|
Цитата negram @ этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4... <?php function f() {} echo "Hello\n"; echo "Version is: " . PHP_VERSION . PHP_EOL; error_reporting(E_ALL); $a = 1; $b = 3; f(&$a, &$b); die("Goodbye!\n"); dps@dps:/var/www/medfiles.ru$ php wrktest.php Hello Version is: 5.3.3-1ubuntu9.1 Goodbye! dps@dps:/var/www/medfiles.ru$ Где обещанный E_DEPRECATED? ____ В любом случае, как авторы PHP предлагают реализовывать функции, семантика вызова которых аналогична таковой у fscanf? |
Сообщ.
#9
,
|
|
|
Цитата Serafim @ у меня. С полными варнингами. Никаких эксепшонов <?php error_reporting(E_ALL); function inc(&$a, &$b){ $a++; $b++; } $a = 41; $b = 25; inc($a, $b); echo $a . '<br />' . $b; Добавлено Цитата negram @ этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4... ты с function [B]&[/B]foo(){} Добавлено Цитата Demon_id @ E_DEPRECATED - и есть ворнинг ну я и говорю - пусто на экране. Точнее на экране требуемый результат |
Сообщ.
#10
,
|
|
|
Цитата Хакер @ ах да, бросается при allow_call_time_pass_reference=falseГде обещанный E_DEPRECATED? Цитата Хакер @ пока-то не придумал. кажется, никак... В любом случае, как авторы PHP предлагают реализовывать функции, семантика вызова которых аналогична таковой у fscanf? Цитата Demon_id @ куда? загляни в лучшые фреймы. |
Сообщ.
#11
,
|
|
|
Цитата negram @ Цитата (Demon_id @ Сегодня, 20:15) загляни в лучшые фреймы. куда? Yii, Zend |
Сообщ.
#12
,
|
|
|
Вопрос:
http://php.net/manual/ru/function.func-get-args.php Цитата 5.3.0 Эта функция теперь может быть использована в качестве параметра функции. Это что значит? о0 Добавлено function foo(func_get_args()){} ???? |
Сообщ.
#13
,
|
|
|
Цитата Serafim @ Раньше ее нельзя было указать другой функции в качестве аргумента... Это что значит? о0 |
Сообщ.
#14
,
|
|
|
Цитата Serafim @ Это что значит? о0 This function can now be used in parameter lists. В смысле её можно передать как «функтор», чтобы функция, которой передана эта, вызвала эту. Всё это никак не имеет отношения к делу, между тем. |
Сообщ.
#15
,
|
|
|
угу, спасибо
Добавлено Цитата Хакер @ Всё это никак не имеет отношения к делу, между тем. Дык скинул ссылку, можно пофаниться и замутить нечто страшное Функции с переменным числом параметров (сообщение #3089051) |