PHP примери за напреднали

  • return; return;
  • continue 2
  • catch(Excepton1|Exception2 $e)
  • isset($param1, $param2, $param3)
  • !empty(array_intersect(['firstname','lastname'], array_keys(array_filter($array))))
  • iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)))
  • preg_match("/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/", $dateString, $coordinates)

Това са функционалности на PHP, които не са описани в началните курсове или не се покриват в повечето уроци свързани с PHP. Исках да извадя някои от скорошните ми способи за подобрение на кода. Всяка една функционалност може да се напише и по друг начин, но с повече редове или по-бавни (както ги срещам най-често). Бих казал, че това са най-кратко написаните решения на даден проблем. Ако все пак някой знае по-добър ще се радвам да го науча.

return; return;

Добре де, return; return; не е всъщност нещо което работи – поне след първия return, но исках да напомня да внимавате за неизпълним код. По-лошото от код който трудно се поддържа е само код, които никога и не се използва. До преди време исках да покрия всичко което правя и да включа допълнителна функционалност – FUTURE PROOF. Но ако имаш 10 такива библиотеки и използваш само 10% от написаното, всъщност ще ти е много трудно да ги поддържаш за в бъдеще (изключения са ако правите Framework, CMS,.. някоя външна библиотека)., защото изискванията винаги се сменят и неизползвания код става все по-голям.

continue 2

Ето това е нещо сравнително просто, което мноого рядко може да ви се наложи, но докато не прочетете в документацията няма да знаете дали можете да го направите. Ако няколко вложени цикъла то единственият начин да прескочите външните е като подадете втори параметър на continue. Това важи и за break. Ето един пример:
for($i = 1; $i <= 3; $i++) {
for($h = 1; $h <= 3; $h++) {
if ($h == 2) continue;
echo $h . " ";
if ($i == 2) continue 2;
}
echo $i . "\n";
}

Така ще получите:

1 1
3 1
1 1 3
3 3

continue може да получи броя на цикли, които трябва да прескочи, като по-подразбиране си е 1.

 

catch(Excepton1|Exception2 $e)

Това е нещо ново – php 7.1+, но ако често използвате try..catch може да ви спести повторения на код. Тук хващаме грешка ако е инстанция на един от 2-та класа.

Може да провчетете документацията за да се запознаете с всички подробности –exceptions

isset($param1, $param2, $param3)

Знаехте ли, че isset може да поема повече от 1 параметър. Накрая връща true само когато всеки един от тях е зададен.

Друг вариант за използването му е да проверите дали елементи в масив съдържат нулеви стойности като isset(...$array)

Документация: isset

!empty(array_intersect(['firstname','lastname'], array_keys(array_filter($array))))

А с този скрипт проверявам дали някои от елементите на списъка са не-празни и се срещат в масив. Ако масива ви е ['firstname' => '', 'lastname' => 'Doe'] ще върне true, но ако е ['firstname' => '', 'middlename' => 'Name'] ще върне false. Удобно е когато изпращате някоя форма да проверите първо дали има не-празни стойности за желаните елементи.

Документация: array_intersect, array_keys, array_filter

iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)))

Обхождането на много-измерни списъци е трудно и винаги се прави с рекурсия, но по този начин с 1 ред код може да вземем плоска версия на масива. Ако искаме просто да обходим всички елементи то можем да извикаме само new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)) и да обходим неговите елементи, понеже може да загубим някои стойности ако имаме едни и същи ключове (Пример: ['key' => 'val', 'other' => ['key' => 'val2']], което ще доведе до ['key' => 'val2'].

Документация: iterator_to_array, RecursiveIteratorIterator, RecursiveArrayIterator

preg_match("/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/", $subject, $matches)

Много често виждам $matches[1]/$matches[0]/$matches[2], което е трудно за четене може да доведе до грешки в някои по-сложни случаи. А така, като подадете ?P<name>директно задавате ключ на параметъраname(а 0,1,2 са си все там, ако желаете да ги използвате).

Документация: preg_match

Надявам се, че вие също ползвате подобни средства, за да улесните живота си. Ако се сещате за нещо подобно, което използвате може да оставите коментар.

, , ,

Няма коментари

Codeception

Лесен и достъпен начин за тестване на вашият код. Предимно за PHP приложения, но не е задължително.

Ако използвате Codeception може да покриете по всякакъв начин вашия код с unit, functional или acceptance тестове.

Документацията им е добре написана и лесно можете да започнете с първите си тестове.

Само като пример (с Composer) бих дал няколко команди които ще създадът всичко необходимо за създаване и изпълнение на Codeceptio тестове:

composer require codeception/codeception --dev
vendor/bin/codecept bootstrap
codecept generate:cept acceptance First
vendor/bin/codecept run

Това ще ви добави библиотеката, чрез Composer.
След това ще създаде стартова версия с unit, functional и acceptance тестови конфигурации.
Генерираме тестов файл с формат Cept за acceptance suit и име First.
Накрая пускаме проверка за всички тестове, които нямат никакви проверки, но все пак всички основни файлове са създадени и може да започнете доректно с покриването на вашия код.

След лекцията ми на RuseConf 2017, реших да дам малко повече публичност на начините за тестове. С тази публикация започвам серия от най-добри практики при писане не стандартни тестове.

Codeception има примерни тестове за много видове проекти, както и за фреймуърковете, които поддържат – Zend, Yii, Phalcon, Doctrene, Laravel, Simpfony, Silex..
Избрах да направя разширена версия на тестовете им на Laravel, за да покажа добри практики за по-напреднали тестове. Можете да я намерите в Github: https://github.com/ibpavlov/codeception-laravel5-advanced

, , , , ,

Няма коментари

JSON_NUMERIC_CHECK round-fix

Ако искате автоматично да преобразувате низове в числа при json_encode тогава един от начините е с JSON_NUMERIC_CHECK.

Но при него има доста често срещани проблеми като изрязването на телефоните и големите числа.

Това се отнася най-вече за запазени в някакъв обект, база от данни, или други които са пресметнати и са представени в консистентен формат. Например: при запазване на числата +123, 0123, 123 винаги ще се запазят като 123. Когато взимаме тези данни ние знаем, че подадените ни данни ще са вече изчислени, обработени и +123 не може да срещнем ако числото наистина не е низ от символи.

Ето една реализация на същата функционалност както при JSON_NUMERIC_CHECK, която не създава такива проблеми. Числата се заменят само ако не са толкова големи и ако не започват с „+“ или „0“ (т.е. са изчислени числа).


Опростената версия на кода:

function stringToNumeric(&$element)
{
    if(is_string($element) && is_numeric($element)) {
        //Check if normal int or float and change format
        if (ctype_digit($element) && strval(intval($element)) === $element) {
            $element = intval($element);
        } elseif(strval(doubleval($element)) === $element) {
            $element = doubleval($element);
        }
    }
}

function arrayStringsToNumeric(&$array) 
{
    array_walk_recursive($array, "stringToNumeric");
}

function jsonNumericEncode($data, $options = 0, $depth = 512)
{
    //if Has Numberic check and is_array do proper check
    if(($options & JSON_NUMERIC_CHECK) == JSON_NUMERIC_CHECK && is_array($data)) {
        //Remove numeric check
        $options = $options ^ JSON_NUMERIC_CHECK;
        //Make proper type
        array_walk_recursive($data, "stringToNumeric");
    }
    json_encode($data, $options, $depth);
}
jsonNumericEncode

Функцията замества използването на JSON_NUMERIC_CHECK, но може и да се ползва директно като премахнете тази проверка.

function prepareJsonData($data)
{
    //if Has Numberic check and is_array do proper check
    if((is_array($data) && !empty($data)) {
        //Make proper type
        array_walk_recursive($data, "stringToNumeric");
    }
}
$data = prepareJsonData($data);
json_encode($data);

Така накрая в данните може да получите

{
    "phone": "+525526262",
    "number: 12512521, 
    "phone2": "0025542424252",
    "money": 22.23
}

вместо

{
    "phone": 525526262,
    "number: 12512521, 
    "phone2": 25542424252,
    "money": 22.23
}

Има и друго решение, което според мен не е толкова ефективно. Можете да продължите с използването на JSON_NUMERIC_CHECK, но да промените малко данните за да се запазят все пак като низ от символи:

function prepareJsonWithNumberCheck(&$data) {
array_walk_recursive($data, function(&$element) {
    //Check if big int or number and add space
    $same = strval(intval($element)) == $element;
    if (ctype_digit($element) && !$same) {
        $element = "" . $element . " ";
    } elseif(!$same && !preg_match('/^(\+|0)[0-9]+$/', $element)) {
        $element = "" . $element . " ";
    }
});
}

, , ,

Няма коментари

Разделяне на локация в 2 отделни полета

Разделяне на локация в 2 отделни полета
от 22.33,21.33 в полетата latitude и longitude

update users_profiles set latitude = cast(SUBSTRING_INDEX(`location`, ',', 1) as decimal(10, 4)), longitude = cast(SUBSTRING_INDEX(location, ',', -1) as decimal(10, 4));

Няма коментари

Bootstrap качване на файл

bootstrap-file-upload-inputДобре изглеждаща форма за качване на файлове.

Ако знаете синтаксиса на Bootstrap може лесно да се промени и да се ползва без бутона за изпращане.

<input type="file" name="excel" id="input_file" style="display:none;" />
<div class="input-group col-sm-4 pull-right">
 <span class="input-group-btn">
     <button class="btn btn-default" id="select_button" type="button">Select...</button>
 </span>
 <input type="text" name="text-excel" readonly="" id="submit_file" class="form-control">
 <span class="input-group-btn">
     <input type="submit" name="upload" value="Import" class="btn btn-primary">
 </span>
</div>
<script>
    $('#input_file').change(function(){
        $('#submit_file').val($(this).val().replace(/C:\\fakepath\\/i, ''));
    });
    $('#select_button').click(function(){
        $('#input_file').click();
    });
</script>

, ,

Няма коментари

  • Страница 1 от 9
  • 1
  • 2
  • 3
  • 4
  • ...
  • 9
  • >