1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.

Посоветуйте как выучить PHP новичку в программировании

Тема в разделе "Программирование", создана пользователем ahdpe, 05.05.20.

  1. qwertEHOK

    qwertEHOK Активный участник

    2.628
    19
  2. The Chief

    The Chief Активный участник

    8.782
    238
    Можно и на комаров охотиться при помощи гаубицы. :) Но вряд ли нужно.

    «У нас было 2 админа, 75 рабочих мест, 5 офисов в разных городах, пол-стойки серверов и целое множество интернет-провайдеров всех сортов и расцветок, балансировка каналов, а также почта, ftp, облачная АТС и 2 дюжины софтфонов. Не то чтобы это был необходимый запас для бизнеса, но если начал предоставлять услуги, становится трудно остановиться. Единственное, что вызывало у меня опасение — это облачная АТС. Ничто в мире не бывает более беспомощным, безответственным и порочным, чем sip-софтфоны. Я знал, что рано или поздно мы перейдем и на эту дрянь».

    Задача — есть некоторое количество IP-софтфонов Acrobits Groundwire. Им нужно получать общий справочник компании. Вариантов аж целых два: либо разворачивать толстожопый сервер CardDAV (99% которых не умеют заполнять адресные книги из LDAP), либо свой собственный Web Service, для которого всего лишь документированы форматы XML и JSON, которые умеет Groundwire.

    Но зачем нам толстожопые серверы протухших лет 10 назад технологий? У нас ведь уже есть nginx и php (самописный портал для самостоятельного WOL-пробуждения офисных компов удалёнщиками). В php есть модуль ldap. К нему есть масса примеров использования. Чего ещё хотеть?
     
  3. The Last Winged

    The Last Winged Активный участник

    12.337
    238
    Вот именно этот момент я и имел ввиду. Добавляете ValueObject'ы по классам (тоже по 1 на файл), разбиваете сплошной блок на классы, делаете точку входа.
    Вы же спрашивали, как научиться делать хорошо, а не как нравится? Надо еще типы везде добавить, использовать исключения вместо die, читать конфиг из ENV или yaml, вынести работу с HTTP отдельно. Но на все это за нарушением кодстайла сложно смотреть.

    В этом и дело. Код же не вам принадлежит, а компании. Поэтому надо, чтобы удобно было не вам, а большинству их тех, кто с ним сталкивается. С учетом большой текучки в IT и длительности жизни решений относительно длительности работы среднего сотрудника это необходимо.

    А еще нужен контейнер какой-либо, если скрипт не одноразовый и на него забьют. Чтобы закрепить версию рантайма. Сейчас не нужно, а через год станет необходимым, т.к. при очередном апдейте чего-то что-то отвалится.
     
    Иной гость нравится это.
  4. E13

    E13 Модератор

    7.102
    301
    Много чего тут по уму написали, я это даже перечитаю потом чтобы над своим кодом подумать дополнительно :)

    Со своей стороны заметил примерно следующее:

    1. Если результирующий объект - JSON, ошибки также должны отдавать JSON
    2. Висяки вроде
    PHP:
    if (условие) {
     
    // длиннокод
    } else {
     
    // ругнуться и выйти
    }
    по мне очень не ок. Ок - вот так:
    PHP:
    if (не-условие) {
     
    // ругнуться и выйти
    }

    // длиннокод
    3. for-цикл тут выглядит жутковато. Возможно, куда правильнее было бы сделать что-то вроде
    PHP:
    $array_contacts array_map(функция_обработки_элемента$data)
    $data перед этим, по-видимости, нужно немного причесать, чтобы исключить лишние элементы из обработки.

    4. Да, классы тут бы очень не помешали.
     
  5. E13

    E13 Модератор

    7.102
    301
    Вот кстати что люто бесит в ПХП в последнее время, что вещи вроде

    PHP:
    условие || exit;
    работают, а, например,

    PHP:
    условие || return;
    - нет

    До ?? додумались, до ?: додумались, казалось бы ещё чуть-чуть - и вообще супер будет. Но что-то нет. Ну или я чего-то не знаю :)
     
  6. The Chief

    The Chief Активный участник

    8.782
    238
    В данном случае — не должны, выхлоп будет сразу съеден web-клиентом, а в нём не определены ошибки в json. Я немного дополнил, теперь при ошибках возвращается в хидере http 404.

    Не разворачивать if? Принято.

    А что не так? Мы набиваем многомерный ассоциативный массив, а потом чохом его вернём json_encode. Сколько вернулось элементов в поиске, говорит элемент 'count' в результате ldap_get_entries.

    Не надо. Мы знаем точно, какие элементы нам нужны в $ldapdata и выбираем их ещё на этапе ldap_search в $attr. Я убрал лишние атрибуты.

    PHP:
    <?php
    function convertBinToMSSQLGuid(string $binguid): string
    {
        
    $unpacked unpack('Va/v2b/n2c/Nd'$binguid);
        return 
    sprintf(
            
    '%08X-%04X-%04X-%04X-%04X%08X',
            
    $unpacked['a'],
            
    $unpacked['b1'],
            
    $unpacked['b2'],
            
    $unpacked['c1'],
            
    $unpacked['c2'],
            
    $unpacked['d']
        );
    }

    $username   'readldapuser';
    $password   '########';
    $server 'ldap://####.local';
    $domain '@####.local';
    $port       389;

    $ldap_connection ldap_connect($server$port);

    if (! 
    $ldap_connection) {
        
    header('HTTP/1.0 404 Not Found');
        echo 
    '<p>LDAP SERVER CONNECTION FAILED</p>';
        exit;
    }

    // Help talking to AD
    ldap_set_option($ldap_connectionLDAP_OPT_PROTOCOL_VERSION3);
    ldap_set_option($ldap_connectionLDAP_OPT_REFERRALS0);

    $ldap_bind = @ldap_bind($ldap_connection$username $domain$password);

    if (! 
    $ldap_bind) {
        
    header('HTTP/1.0 404 Not Found');
        echo 
    '<p>LDAP BINDING FAILED</p>';
        exit;
    }

    $base_dn 'DC=#####,DC=local';

    $filter '(&(objectCategory=person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))(|(ipPhone=*)))';

    $attr = array('sn''givenname''displayname''objectguid''ipPhone');

    $result ldap_search($ldap_connection$base_dn$filter$attr);

    if (! 
    $result) {
        
    header('HTTP/1.0 404 Not Found');
        echo 
    '<p>LDAP SEARCH FAILED</p>';
        exit;
    }

    $ldapdata ldap_get_entries($ldap_connection$result);

    if (
    $ldapdata['count'] == 0) {
        
    header('HTTP/1.0 404 Not Found');
        echo 
    '<p>No results found!</p>';
        exit;
    }

    $array_contacts = array();
     
    for (
    $i 0$i $ldapdata['count']; $i++) {
        
    $array_person = array();
        
    $array_person['contactEntries'] = array(array(
        
    'entryId' => 'tel:0',
        
    'label' => 'Внутренний',
        
    'type' => 'tel',
        
    'uri' => ($ldapdata[$i]['ipphone'][0])
        ));
        
    $array_person['contactId'] = convertBinToMSSQLGuid($ldapdata[$i]['objectguid'][0]);
        
    $array_person['countryCode'] = 'ru';
        
    $array_person['displayName'] = $ldapdata[$i]['displayname'][0];
        
    $array_person['fname'] = $ldapdata[$i]['givenname'][0];
        
    $array_person['lname'] = $ldapdata[$i]['sn'][0];
        
    array_push($array_contacts$array_person);
    }
        
    $json json_encode(array('contacts' => $array_contacts), JSON_PRETTY_PRINT JSON_UNESCAPED_UNICODE);
        
    header('Content-Type: application/json; charset=utf-8');
        
    header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
        echo 
    $json;
     
  7. E13

    E13 Модератор

    7.102
    301
    С точки зрения решения задачи - всё ок. С точки зрения получения легкочитаемого кода - не ок.

    Просто для сравнения
    PHP:
    $a = [];
    for (
    $i 0$i $ldapdata['count']; $i++) {
        
    $a[] = $ldapdata[$i];
    }
    против
    PHP:
    $a = [];
    foreach (
    $ldapdata as $item) {
        
    $a[] = $item;
    }
    Второй вариант смотрится и читается легче. Меньше кода => добро

    А в последнее время я вообще стараюсь не использовать циклы, решая задачки как-то так:
    PHP:
    $array array_map(function($item) {
            return 
    $item
        
    }, $data);
    Такое порой в одну строку позволяет сворачивать блоки, которые при "старом" подходе заняли бы 5-6-10 строк. Особенно хорошо в новом синтаксисе (пхп 7.4+):
    PHP:
    $array array_map(fn($item) => $item$data);
    Правда, тут нужно избавиться от лишних элементов вроде $ldapdata['count']: проитерироваться можно и без них, и если их не убрать, они тоже появятся при перечислении.

    Если говорить про дальнейшую оптимизацию, то данные для подключения можно убрать в отдельный пхп-файл или в какой-нибудь JSON, сократив
    PHP:
    $username   'readldapuser';
    $password   '########';
    $server 'ldap://####.local';
    $domain '@####.local';
    $port       389;
    до
    PHP:
    $creds json_decode(file_get_contentspath-to-file.json ))
    или
    PHP:
    $creds incude(path-to-file.php)
    или
    PHP:
    extract(incude(path-to-file.php));
    Хотя последнее на мой взгляд не очень ок, так как не видно, с какими переменными в итоге через него можно будет поработать.

    Затем (если продолжать оставаться в процедурном подходе) обобщить аварийные завершения в функцию, получив что-то вроде
    PHP:
    if ($ldapdata['count'] == 0) {
        
    exit404('No results found!')
    }
    или если бесят простые условия:
    PHP:
    checkIfExit404($ldapdata['count'] == 0'No results found!')
    саму функцию определив как
    PHP:
    function checkIfExit404($check$message) {
        if (!
    $check) return;
        
    header('HTTP/1.0 404 Not Found');
        echo 
    $message;
        exit;
    }
    И, кстати, если не обязательно показывать 404, можно было бы вообще
    PHP:
    $ldapdata['count'] == || exit('No results found!')
    Работу с данными в цикле тоже хочется как-то переписать, как минимум - подготовив где-то снаружи объект со статическими данными и тем самым уменьшив количество кода в цикле.
     
  8. The Chief

    The Chief Активный участник

    8.782
    238
    А в for не нужно. И вообще, религиозная ненависть к for мне непонятна. Я тоже люблю и использую foreach там, где это уместно (мои говноскрипты на powershell состоят из foreach чуть менее, чем полностью).

    Если будет в дальнейшем необходимость — конечно, замечание разумное. Пока что её нет, с AD работает только этот модуль.

    А вот тут я против. Никак его не уменьшить, и так одна строка кода на один элемент данных (с заменой namespace). Только наплодить совершенно ненужных в данном случае объектов.

    И тоже принято.

    В теории — необязательно, достаточно не вернуть клиенту верный json (это не документировано). Но я не хочу лишний раз напрягать клиента парсингом. 404 и ойвсё.

    @E13, и ещё я избавился от лишней инициализации массива array_person. Теперь так:
    PHP:
    for ($i 0$i $ldapdata['count']; $i++) {
        
    array_push($array_contacts, array(
        
    'contactEntries' => array(array(
        
    'entryId' => 'tel:0',
        
    'label' => 'Внутренний',
        
    'type' => 'tel',
        
    'uri' => $ldapdata[$i]['ipphone'][0]
        )),
        
    'contactId' => convertBinToMSSQLGuid($ldapdata[$i]['objectguid'][0]),
        
    'countryCode' => 'ru',
        
    'displayName' => $ldapdata[$i]['displayname'][0],
        
    'fname' => $ldapdata[$i]['givenname'][0],
        
    'lname' => $ldapdata[$i]['sn'][0]
        ));
    }
     
  9. E13

    E13 Модератор

    7.102
    301
    У меня есть ряд правил, которыми стараюсь руководствоваться. Например, более простой код лучше, чем более сложный. В этом смысле for проигрывает. В теории от него вообще можно избавиться, даже там, где нужна итерация по диапазону.

    Как минимум, в цикле на каждой итерации присваиваются одни и те же данные. Я про entryId, label, итп
     
  10. The Chief

    The Chief Активный участник

    8.782
    238
    Ну не настолько это фатально, чтобы плодить классы. Кода всё равно будет больше.
     
  11. The Last Winged

    The Last Winged Активный участник

    12.337
    238
    Классы "плодят" не потому что "азаза классы лол", а чтобы качество кода улучшить.
    Зачем спрашивать вопросы, если все равно не собираешься улучшать код по советам?
     
  12. 027

    027 Активный участник

    4.074
    801
    Мне прежде всего бросился в глаза спагетти-стайл. Для одноразовых наколенных поделок годится, но если эта малая автоматизация имеет шансы прожить долго (и неизбежно переделываться) поддержка лапши превращается в аццкий адъ.

    Процедурный стиль вполне достойная вещь, но и в нем уместно разносить логику и вывод. Вовсе не обязательно тащить в каждый скриптик MVC, но хотя бы выделить представление в отдельную сущность — сам себе потом спасибо скажешь.

    Я, как и всякий непрограммист, которому довелось работать с пыхом, всё это проходил, радостно лепя echo прямо в функциях обработки данных и переключая контекст где попало.

    Много проклятий было к самому себе потом.

    И таки да, класс удобнейшая штука, когда задолбаешься выдумывать имена к расплодившимся, как тараканы, функциям и переменным.
     
    Последнее редактирование: 01.10.20
    Иной гость нравится это.
  13. имя

    имя Активный участник

    12.058
    1.515
    Жиза Screenshot_20201008_103049.jpg
     
    027 и Иной гость нравится это.
  14. E13

    E13 Модератор

    7.102
    301
    Хех. Вот прямо недавно: набираем норот в команду. Оплата не то что бы большая, но для миддлов приемлемая по рынку.

    Жду от людей некоторой мотивированности и экспертизы: сам платил куда меньше, и примерно представляю, что должны уметь чуваки ценовой категории х2. Приходит чел. Начинаем работать - вроде норм, рекомендации с его стороны, по чуть рефакторинга. Но не сильно быстро всё пилит. Ок, может, в проекте разбирается пока.

    Даю задачку: сохранить некоторый сложный объект (сущность + пачка связанных с ней). Проходит день, второй. Пишу: чокагдила? Он: рефакторить надо, сейчас задачу решить не получится. Я: чо, рили, просто в базу сохранить не получится никак? (при том, что даже код уже есть, его по чуть адаптировать - и оп) Он: за говнокодом к индусам, тут уже проблемы, а дальше будет больше.

    Пришлось челу как раз примерно на картинке нарисовано пояснения давать. Что если сразу красиво не получается, надо сдать задачу, а красивостями заниматься уже потом. Хотя на деле скорее всего проблема была тупо в том, что чел параллельно чем-то занимался (не то ещё проект какой вёл, не то в носу ковырял, хз). В итоге разраб психанул, написал чота там негативное боссу, что в индусов играть без него. И проработав неделю был выдворен из проекта.

    Ну и особенный лулз в том, что из трёх людей, которых пытались нанять, ни один не оказался адекватным. Последний кто держится тоже работает со скоростью полчерепахи в час, но очень обстоятельно отчёты рисует. Так, что, не зная реальный объём кода и усилий на него, можно подумать, что реально работает, ахаха
     
  15. legatus

    legatus Активный участник

    4.520
    2.330
    Скорее не работал в крупных проектах и нет опыта \ знаний работы с чужим кодом. Или банально не нравиться этим заниматься.
     
  16. Дмитрий Н

    Дмитрий Н Активный участник

    1.556
    245
    Представляю его версию произошедшего: "Устроился вроде в нормальную команду, а спустя неделю понял, что они гонят лютый говнокод на скорость, решил не затягивать и попрощался с ними".
     
    ski нравится это.
  17. Иной гость

    Иной гость Активный участник

    21.545
    3.055
    Никаких русских программистов не хватит переписывать говнокод за индусами. Иногда надо смириться и работать на том, что есть.
     
  18. E13

    E13 Модератор

    7.102
    301
    Я бы поставил на то, что не тем был занят человек, и использовал рефактор как отговорку. Потому что даже при плохом коде оно обычно работает иначе: в самом начале задачи чел пишет "ребят, тут что-то у вас не то, я предлагаю вот так разрулить, займёт столько-то". Собственно, этот товарищ так и делал поначалу.

    Потом пошёл негатив (босс запрашивал два мита в день, чел начал намекать, что это лишнее), потом я его пушнул по срокам, ну и стало ясно, что сейчас что-то неконструктивное начнётся. Возможно, он просто ждал большего от проекта и искал какую-то крутую команду, а тут мы с тусовкой в 2.5 юнита и проектом, который не то что бы большой и сложный.

    Менеджер - это априори виноватый человек :)

    Вписался раз в проект, который шёл под заголовком "три штуки за неделю". Чел предлагал допилить какой-то каталог. Каталог на вордпрессе, его мы знаем вдоль и поперёк, кеш хороший, чо б не взяться? Затем заглянул под капот, а там даже стандартные библиотеки неким старательным индусом подправлены так, что пришлось извиняться и отказываться.
     
  19. The Last Winged

    The Last Winged Активный участник

    12.337
    238
    Индусы по некоторым аспектам лучше русских работают. В частности софт-скиллс.