Пятничная PHP-викторина: немного приключений программиста Брэда, одна странная последовательность и призы

    Привет! Обещали — делаем: продолжаем серию мини-квизов, посвященных разным языкам программирования в нашем блоге (предыдущие: 1 (на знание Python, PHP, Golang и DevOps), 2 (полностью по Go)). Сегодняшний выпуск посвящён PHP.

    Под катом — восемь вопросов, немного приключений программиста Брэда, одна странная последовательность и клёвый мерч в качестве призов. Квиз проходит до 4 июля.

    UPD 2: Как и договаривались, выкладываем разбор заданий викторины. Пояснения скрыли под спойлером после правильных ответов. Если у вас остались вопросы, задавайте их в комментариях.

    UPD: Мы закончили принимать ответы. Спасибо всем, кто поучаствовал! Мы готовим разбор заданий. Ответы на них — внутри текста, а победители и призеры под спойлером.
    Победители и призеры PHP-викторины

    Победитель


    egor_nullptr

    Призеры


    Мы случайным образом выбрали десять лучших участников, допустивших не больше двух ошибок в ответах: Dimd13, slimus, alexchromets, Donquih0te, TexElless, SamDark, AdmAlexus, voiceofnoise, Raz-Mik, Serj_By.

    Запись розыгрыша


    Бонус!


    Тем, кто допустил всего одну ошибку, мы дополнительно дарим холиварные кости, с которыми можно решить на каком бэкенд-языке и фронтенд-фреймворке писать ваш новый проект/или переделать старый. Их получают: DjSebas, TexElless, Turik-us, offlinewan, voiceofnoise, andrey_96, delight-almighty.




    Правила игры


    Первому, кто правильно ответит на них, отправим набор сувенирки Авито: футболку с php-слоном, носки и холиварные кости (можно будет погадать, на каком бэкенд-языке и фронтенд-фреймворке будет написан ваш новый проект).

    Десяти другим правильно ответившим отправим Авито-носки. Разыграем с помощью рандомайзера. Он же определит, к кому поедут ещё две футболки и набор костей.



    Вопросы и варианты ответов


    Вопрос 1


    Что выведет код:

    <?php
    $a = [1, 2, 3];
    foreach($a as &$value) {}
    foreach($a as $value) {}
    
    print_r($a);
    

    Варианты ответов:

    1. Array(1, 2, 3)
    2. Array(1, 2, 2)
    3. Array(3, 2, 1)
    4. Ошибка

    Правильный ответ
    Array(1, 2, 2)

    Объяснение
    Поскольку в php переменные созданные в цикле остаются жить после его завершения, к началу второго цикла переменная $value — это ссылка на последний элемент массива. Во время итерации последнего foreach значения из массива записываются в его последний элемент (т.к. $value — это ссылка). Так будет выглядеть массив на каждой итерации второго цикла:
    1. [1, 2, 1]
    2. [1, 2, 2]
    3. [1, 2, 2]

    Вопрос 2


    Что выведет код:

    <?php
    function sowCrops() { return 'wheat'; }
    function millWheat() { return 'flour'; }
    function bake($flour) { return 'cupcake'; }
    function generator() {
        $flour = yield millWheat();
        $wheat = yield sowCrops();
        return bake($flour);
    };
    $gen = generator();
    foreach ($gen as $key => $value) {
        echo $key . ' => ' . $value . PHP_EOL;
    }
    echo $gen->getReturn();
    

    Варианты ответов:

    1.  0 => flour
       1 => wheat
      

    2.  0 => wheat
       1 => flour
       2 => cupcake
      

    3. 0 => flour
      1 => wheat
      cupcake 
      

    4. cupcake



    Правильный ответ
    4.
    0 => flour
    1 => wheat
    cupcake 
    



    Объяснение
    No comments. Просто немного мудрёный пример с генераторами.

    Вопрос 3


    Однажды программист Брэд решил портировать одну библиотеку с Go на PHP, чтобы собрать звёзд на GitHub, и задался вопросом:

    Возможна ли следующая конструкция?

    <?php 
    print_r(...(new Foo()));

    Варианты ответов:

    1. Да, класс Foo должен реализовать интерфейс Traversable
    2. Да, класс Foo должен реализовывать методы интерфейса ArrayAccess
    3. Нет, будет ошибка, аргумент ...-оператора должен быть массивом

    Правильный ответ
    1. Да, класс Foo должен реализовать интерфейс Traversable

    Объяснение
    Тут всё просто. Из документации Argument Unpacking:
    Массивы и объекты, реализующие интерфейс Traversable могут быть распакованы в список аргументов при передаче в функцию с помощью оператора ...


    Вопрос 4


    Какой алгоритм сортировки используется в сердце PHP для таких функций, как sort и тд?

    Варианты ответов:

    1. нерекурсивный mergesort
    2. heapsort (вариация smoothsort Эдсгера Дейкстры)
    3. quicksort с разбиением по медиане из трех
    4. introsort

    Правильный ответ
    4. introsort

    Объяснение
    Используется introsort. Исходный код можно посмотреть на Гитхабе. В документации есть упоминание об использовании quicksort, но тут нет противоречия, ведь introsort — гибридный алгоритм сортировки, где при малом количестве элементов используется сортировка вставкой, а позже используется более быстрый алгоритм: quicksort или heapsort.


    Вопрос 5


    Есть код:

    <?php
    class Factory {
        public function getLambda(): Closure {
            return function () {
                printf("Here I am (%s)!\n", get_class($this));
            };
        }
    
        public function getLambda2(): Closure {
            return static function () {
                printf("Here I am (%s)!\n", get_class($this));
            };
        }
    }
    

    Вопрос: есть ли разница между возвращаемыми значениями getLambda и getLambda2?

    Варианты ответов:

    1. В одном случае использовано ключевое слово static :), но оно никак не влияет
    2. Результат getLambda2() нельзя привязать к какому-нибудь объекту
    3. Так нельзя писать: будет синтаксическая ошибка «Syntax error: static keyword used in wrong context»
    4. Closure из getLamda2() можно привязывать (bindTo) только к классам

    Правильный ответ
    2. Результат getLambda2() нельзя привязать к какому-нибудь объекту

    Объяснение
    Метод getLambda2() возвращает статическую анонимную функцию, которую нельзя привязать к объекту через ->bindTo() метод. Их использование редко встречается в коде, но всё же

    Вопрос 6


    Что выведет код:

    <?php
    
    $a = true;
    $b = false;
    
    $c = $a and $b;
    $d = $a && $b;
    
    var_dump($c);
    var_dump($d);
    

    Варианты ответов:

    1. bool(false)
      bool(false)
      
    2. bool(false)
      bool(true)
      
    3. bool(true)
      bool(true)
      
    4. bool(true)
      bool(false)
      

    Правильный ответ
    4.
    bool(true)
    bool(false)
    


    Объяснение
    Разница между && и and в приоритете. Выражение $d = $a && $b работает как $d = ($a && $b). А вот выражение $c = $a and $b работает иначе и может быть представлено в виде (($c = $a) and $b).

    Вопрос 7


    Что выведет код:

    <?php
    
    $a = 'a';
    
    for ($i = 0; $i < 40; $i++) {
        echo $a++, PHP_EOL;
    }
    

    Варианты ответов:

    1. Будут выведены цифры от 0 до 39, а также Warning: A non-numeric value encountered in на каждой итерации
    2. Каждая итерация выведет ‘a’ + Warning
    3. Странная последовательность:
      a
      b
      c
      d
      e
      f
      g
      h
      i
      j
      k
      l
      m
      n
      o
      p
      q
      r
      s
      t
      u
      v
      w
      x
      y
      z
      aa
      ab
      ac
      ad
      ae
      af
      ag
      ah
      ai
      aj
      ak
      al
      am
      an

    Правильный ответ
    3. Странная последовательность:
    a
    b
    c
    d
    e
    f
    g
    h
    i
    j
    k
    l
    m
    n
    o
    p
    q
    r
    s
    t
    u
    v
    w
    x
    y
    z
    aa
    ab
    ac
    ad
    ae
    af
    ag
    ah
    ai
    aj
    ak
    al
    am
    an


    Объяснение
    Не все знают, но оператор инкремента можно применять к символам. Из документации:
    PHP следует соглашениям Perl (в отличие от С) касательно выполнения арифметических операций с символьными переменными. Например, в PHP и Perl $a = 'Z'; $a++; присвоит $a значение 'AA', в то время как в C a = 'Z'; a++; присвоит a значение '[' (ASCII-значение 'Z' равно 90, а ASCII-значение '[' равно 91).


    Вопрос 8


    Что выведет код:

    <?php
    
    class TestMe {
        public function test()
        {
            if (0) {
                yield 32332;
            }
    
            return [1,2,3];
        }
    }
    
    $t = new TestMe();
    
    foreach ($t->test() as $id) {
        echo $id, PHP_EOL;
    }
    
    echo "The end", PHP_EOL;
    

    Варианты ответов:

    1. 1
      2
      3
      32332
      The end
      

    2. 1
      2
      3
      The end
      

    3. The end
      

    4. 32332
      The end
      


    Правильный ответ
    3.
    The end
    



    Объяснение
    С первого взгляда может показаться, что функция не возвращает генератор, потому что yield выражение недостижимо. Однако, любая функция содержащая yield выражение автоматически становится функцией-генератором. В оригинальном RFC так и написано. В момент первой итерации генератор начинает выполнять код функции с самого начала до первого доступного yield выражения, но поскольку его нет, генератор заканчивает свою работу, так и не передав какие-либо данные в цикл.

    Подведение итогов


    Ответы на вопросы выложим апдейтом к посту в среду, 4 июля. Если будете решать — кладите ответы под спойлер, чтобы не портить другим фана. И не забывайте проверять личку Хабра после окончания квиза.

    Enjoy!
    Avito 272,55
    У нас живут ваши объявления
    Поделиться публикацией
    Похожие публикации
    Комментарии 42
      +2
      На вопрос 2 нет правильного ответа. Должно быть
      0 => flour
      1 => wheat
      cupcake
      
        0
        Да, исправил. Спасибо за внимательность :)
        0
        Заголовок спойлера
        1) 2
        2) 3
        3) 1
        4) 3
        5) 4
        6) 4
        7) 3
        8) 3
          0
          Заголовок спойлера
          2 3 1 3 4 4 3 3
            0
            Не ошибка ли в вариантах ответа третьего вопроса?
            Заголовок спойлера
            1. 2
            2. 3
            3. 1 (но подозреваю, что ошибка в вариантах ответа — даже без имплементации Traversable должно работать, выбрал этот вариант, как самое слабое условие)
            4. 3
            5. 4
            6. 4
            7. 3
            8. 3
              0
              Заголовок спойлера
              • 2
              • 3
              • 1
              • 3
              • 4
              • 4
              • 3
              • 3

                0
                Один
                Array ( [0] => 1 [1] => 2 [2] => 2 )

                Два
                Parse error: syntax error, unexpected 'millWheat' (T_STRING)

                Три
                Foo Object ( )

                Четыре
                Для сортировки PHP использует реализацию quicksort, которая может быть найдена в Zend/zend_qsort.c, которая выполняет функцию сравнения и массив элементов, Функция сравнения по умолчанию для sort() определена в ext/standard/array.c и называется php_array_data_compare(). В принципе, это тот же алгоритм для всех функций сортировки, за исключением того, что они выполняют разные функции сравнения.


                Шесть
                bool(true) bool(false)

                Семь
                3. Странная последовательность

                  0
                  Заголовок спойлера
                  1. 2
                  2. 3
                  3. 1
                  4. 3
                  5. 4
                  6. 4
                  7. 3
                  8. 3
                    0
                    Заголовок спойлера
                    1. 2
                    2. 3
                    3. 1
                    4. 3
                    5. 4
                    6. 4
                    7. 3
                    8. 3
                      0
                      Ответы
                      1 — 2
                      2 — 3
                      3 — 1
                      4 — 3
                      5 — 4
                      6 — 4
                      7 — 3
                      8 — 3
                        0
                        спойлер
                        2
                        3
                        1
                        3
                        4
                        4
                        3
                        3
                          0
                          спойлер
                          1-1
                          2-3
                          3-3 Навскидку
                          4-1 навскидку
                          5-4
                          6-4
                          7-3
                          8-3
                            0
                            Заголовок спойлера
                            1. 2
                            2. 3
                            3. 1
                            4. 4
                            5. 2
                            6. 4
                            7. 3
                            8. 3
                              0
                              Заголовок спойлера
                              1) 2
                              2) 3
                              3) 1
                              4) 3
                              5) 4
                              6) 4
                              7) 3
                              8) 3
                                0
                                Ответ
                                1/2, 2/3, 3/1, 4/3, 5/4, 6/4, 7/3, 8/3.
                                  0
                                  Заголовок спойлера
                                  1) 2
                                  2) 3
                                  3) 1
                                  4) 3
                                  5) 4
                                  6) 4
                                  7) 3
                                  8) 3
                                    0
                                    Скрытый текст
                                    1.2
                                    2.3
                                    3.1
                                    4.3
                                    5.4
                                    6.4
                                    7.3
                                    8.3
                                      +1
                                      Заголовок спойлера
                                      1) Ответ: 2. Array(1, 2, 2) т.к. во втором переборе в $value находится ссылка на последний элемент массива при первом переборе

                                      2) Ответ: 3. В 7 пыхе генераторы довольно сильно расширили, теперь можно получать делать getReturn. Давно не писал на 5, долго искал в чем подвох в задаче.

                                      3) Ответ: 1. На сколько я помню оператор… разворачивает итерабельные. А интерфейс Traversable напрямую вообще нельзя реализовывать.

                                      4) Ответ: 3.

                                      5) Ответ: 2. К статичным замыканиям нельзя биндить инстансы.

                                      6) Ответ: 4. Тут подвох в приоритете операторов. Хоть операторы && и and похожи они имеют разные приоритеты. Из-за этого в выражении $c = $a and $b; сначала будет присвоено значение переменной $c.

                                      7) Ответ: 3. Привет Perl)

                                      8) Ответ: 3. Ключевое слово yield будет означать что данный метод вернет генератор. Который ничего не выбросит.
                                        0
                                        Spoiler

                                        2 3 1 3 4 4 3 3

                                          +1
                                          Ответы и чуть-чуть комментов для неочевидного
                                          1) 2 (но можно сделать unset($value) между циклами, чтобы пофиксить)
                                          2) 3
                                          3) 1
                                          4) 3
                                          5) $this нельзя использовать в контексте static функции, подозреваю что это 2
                                          6) 4 (потому что у and приоритет ниже чем у присваивания)
                                          7) 3 (да, пхп инкрементит строки по алфавиту)
                                          8) 3 (потому что test() возвращает генератор, но yield никогда не вызовется)
                                            0
                                            Заголовок спойлера
                                            1. 2
                                            2. 3
                                            3. 1
                                            4. 3
                                            5. 3
                                            6. 1
                                            7. 3
                                            8. 3
                                              0
                                              ответы
                                              1- 2
                                              2- 3
                                              3- 1
                                              4- 3
                                              5- 2
                                              6- 4
                                              7- 3
                                              8- 3
                                                0
                                                Заголовок спойлера
                                                1-2
                                                2-3
                                                3-2
                                                4-3
                                                5-4
                                                6-4
                                                7-3
                                                8-3
                                                  0
                                                  Заголовок спойлера
                                                  2 3 1 3 4 4 3 3
                                                    0
                                                    По второму вопросу: какая версия PHP имеется в виду?
                                                    Ведь из документации:
                                                    Предостережение
                                                    Если вы используете «yield» в контексте выражения (например, в правой части оператора присвоения), вы должны окружить «yield» круглыми скобками. Например, так правильно:
                                                    $data = (yield $value);

                                                    А вот это неправильно и вызовет ошибку синтаксиса в PHP 5:
                                                    $data = yield $value;

                                                    В PHP 7 этого ограничения нет.
                                                      +1
                                                      Речь про PHP 7
                                                      0
                                                      1- 2
                                                      2- 3
                                                      3- 1
                                                      4- 3
                                                      5- 4
                                                      6- 4
                                                      7- 3
                                                      8- 3
                                                        0
                                                        Заголовок спойлера
                                                        1. 2
                                                        2. 3
                                                        3. 1
                                                        4. 3
                                                        5. 3
                                                        6. 1
                                                        7. 3
                                                        8. 3
                                                          0
                                                          Заголовок спойлера

                                                          1 — 2
                                                          2 — 3
                                                          3 — 1
                                                          4 — 3
                                                          5 — 4
                                                          6 — 4
                                                          7 — 3
                                                          8 — 3

                                                            0
                                                            PHP - зло, но приятное и доброе
                                                            1. 2
                                                            2. 3
                                                            3. 1
                                                            4. 3
                                                            5. 4
                                                            6. 4
                                                            7. 3
                                                            8. 3
                                                              0
                                                              Ответы
                                                              1. 2
                                                              2. 3
                                                              3. 1
                                                              4. 3
                                                              5. 2
                                                              6. 4
                                                              7. 3
                                                              8. 3
                                                                0
                                                                Заголовок спойлера
                                                                1. 2
                                                                2. 3
                                                                3. 1
                                                                4. 3
                                                                5. 2
                                                                6. 4
                                                                7. 3
                                                                8. 3
                                                                  0
                                                                  спойлер
                                                                  1) 2
                                                                  2) 3
                                                                  3) 1
                                                                  4) 3
                                                                  5) 2
                                                                  6) 4
                                                                  7) 3
                                                                  8) 3
                                                                    0
                                                                    Заголовок спойлера
                                                                    1. 2
                                                                    2. 3
                                                                    3. 1
                                                                    4. 3
                                                                    5. 4
                                                                    6. 4
                                                                    7. 3
                                                                    8. 3
                                                                      0
                                                                      Заголовок спойлера
                                                                      1-2
                                                                      2-3
                                                                      3-1
                                                                      4-3
                                                                      5-2
                                                                      6-4
                                                                      7-3
                                                                      8-3
                                                                        0
                                                                        1. 2
                                                                        2. 3
                                                                        3. 1
                                                                        4. 3
                                                                        5. 4
                                                                        6. 4
                                                                        7. 3
                                                                        8. 3
                                                                          0
                                                                          А будет объяснено почему именно так работает код?
                                                                            +1
                                                                            Да, конечно объясним
                                                                            0
                                                                            Заголовок спойлера
                                                                            2
                                                                            3
                                                                            1
                                                                            3
                                                                            4
                                                                            4
                                                                            3
                                                                            3
                                                                              0
                                                                              Заголовок спойлера
                                                                              1 — 2
                                                                              2 — 3
                                                                              3 — 1
                                                                              4 — 3
                                                                              5 — 4
                                                                              6 — 4
                                                                              7 — 3
                                                                              8 — 3
                                                                                0
                                                                                Сесурити
                                                                                1 — 2
                                                                                2 — 3
                                                                                3 — 1
                                                                                4 — 3
                                                                                5 — 4
                                                                                6 — 4
                                                                                7 — 3
                                                                                8 — 3
                                                                                  0
                                                                                  Ответы. Надеюсь правильные. :)
                                                                                  1. 2
                                                                                  2. 3
                                                                                  3. 1
                                                                                  4. 3
                                                                                  5. 4
                                                                                  6. 4
                                                                                  7. 3
                                                                                  8. 3

                                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                  Самое читаемое