На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Serafim, fatalist
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
    > Функции с переменным числом параметров , Принимающие эти параметры по ссылке, и способные их менять.
      Представьте себе функцию, которая принимает значение «по ссылке» и способна как-то влиять на это значение.
      Например представьте себе такую надуманную функцию, как increment_this_one. Эта функция — надуманный пример — увеличивает значение, ссылка на которое передана, на единицу.


      ExpandedWrap disabled
        function increment_this_one(&$foo)
        {
           $foo++;
        }


      Замечательно, теперь мы можем сделать что-то подобное:
      ExpandedWrap disabled
        $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, и её суть в том, что она увеличивает все значения, ссылки на которые были переданы.

      Разумеется, в реальности у меня совершенно иная функция, но для простоты ведения топика будем использовать именно этот надуманный пример.

      ExpandedWrap disabled
        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:
      ExpandedWrap disabled
        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-а:
      ExpandedWrap disabled
        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) передали.
        Ну вот и поговорили :lol:

        По сути дела по моему проще уже массив в функцию передавать...
          Цитата fatalist @
          По сути дела по моему проще уже массив в функцию передавать...

          Нет, не пойдёт.

          Уж лучше такой workaround, малозаметный, чем каждый раз писать

          $this->SomeEvent->NotifySubscribers(array(пара-тройка-параметров));
          вместо
          $this->SomeEvent->NotifySubscribers(пара-тройка-параметров);
            Цитата Хакер @
            &$a, &$b, &$c
            этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4...
              Цитата negram @
              Цитата (Хакер @ Сегодня, 19:40)
              &$a, &$b, &$c
              этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4...

              ну так ясен ) передачу параметров по ссылке через амерсенд отменили.


              Цитата Хакер @
              Нет, не пойдёт.

              Уж лучше такой workaround, малозаметный, чем каждый раз писать



              загляни в лучшые фреймы. там именно передача массивов преобладает.
                Просто так, ради фана: http://www.php.net/manual/ru/function.runk...on-redefine.php

                Добавлено
                только оно в пекле валяется

                Добавлено
                Цитата negram @
                этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4...

                работаэ о0

                Добавлено
                у меня. С полными варнингами. Никаких эксепшонов
                  Цитата Serafim @
                  у меня. С полными варнингами. Никаких эксепшонов

                  E_DEPRECATED - и есть ворнинг
                    Цитата negram @
                    этот код бросает E_DEPRECATED в php 5.3 и не работает в 5.4...


                    ExpandedWrap disabled
                      <?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");


                    ExpandedWrap disabled
                      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?
                      Цитата Serafim @
                      у меня. С полными варнингами. Никаких эксепшонов

                      ExpandedWrap disabled
                        <?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...

                      ты с
                      ExpandedWrap disabled
                        function [B]&[/B]foo(){}
                      случайно не перепутал? :huh:

                      Добавлено
                      Цитата Demon_id @
                      E_DEPRECATED - и есть ворнинг

                      ну я и говорю - пусто на экране. Точнее на экране требуемый результат
                      Сообщение отредактировано: Serafim -
                        Цитата Хакер @
                        Где обещанный E_DEPRECATED?
                        ах да, бросается при allow_call_time_pass_reference=false

                        Цитата Хакер @
                        В любом случае, как авторы PHP предлагают реализовывать функции, семантика вызова которых аналогична таковой у fscanf?
                        пока-то не придумал. кажется, никак... :unsure:
                        Цитата Demon_id @
                        загляни в лучшые фреймы.
                        куда?
                          Цитата negram @
                          Цитата (Demon_id @ Сегодня, 20:15)
                          загляни в лучшые фреймы.
                          куда?

                          Yii, Zend
                            Вопрос:
                            http://php.net/manual/ru/function.func-get-args.php
                            Цитата
                            5.3.0 Эта функция теперь может быть использована в качестве параметра функции.

                            Это что значит? о0

                            Добавлено
                            function foo(func_get_args()){} ???? :blink: :wacko:
                              Цитата Serafim @
                              Это что значит? о0
                              Раньше ее нельзя было указать другой функции в качестве аргумента...
                                Цитата Serafim @
                                Это что значит? о0

                                This function can now be used in parameter lists.
                                В смысле её можно передать как «функтор», чтобы функция, которой передана эта, вызвала эту.

                                Всё это никак не имеет отношения к делу, между тем.
                                Сообщение отредактировано: Хакер -
                                  угу, спасибо

                                  Добавлено
                                  Цитата Хакер @
                                  Всё это никак не имеет отношения к делу, между тем.

                                  Дык скинул ссылку, можно пофаниться и замутить нечто страшное :crazy:
                                  Функции с переменным числом параметров (сообщение #3089051)
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0654 ]   [ 15 queries used ]   [ Generated: 27.04.24, 10:17 GMT ]