Jul 18

В по-голямата част от PHP кода ми е OOP. Но все пак имам и няколко функции, като три от тях бих искал да споделя тук. Те са tag / func_array_cut / profile.

Функцията tag

Както се и казва функцията tag генерира html тагове. Тъй като в 99% от времето PHP връща html, е много важно да имам нещо с което бързо и лесно да си създавам тагове. Основно тази функция я използвам в различни помощни методи:

function tag($tag, $options, $content = null){
    if (is_string($options) && !is_string($content)){
        list($content, $options) = array($options, $content);
    }

    $attributes = '';

    if (is_string($options)){
        $attributes = ' ' . $options;
    } else if (is_array($options)){
        foreach($options as $key => $value){
            $attributes .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, 'utf-8') . '"';
        }
    }

    return '<' . $tag . $attributes . (is_string($content) || strlen($content) > 0 ? ">{$content}</{$tag}>" : ' />');
}

Таg може да се извиква по няколко начина, като основната ми идея беше да не се налага да се замислям кои аргумент какъв е – атрибут или текст.

// <input type="text" value="text" />
tag('input', array('type' => 'text', 'value' => 'text'));

// <input type="text" value="&quot;qoute&quot; text" />
tag('input', array('type' => 'text', 'value' => '"qoute" text'));

// <div>content in div</div>
tag('div', 'content in div');

// 3 начина за генериране на
// <a href="http://www.pixeldepo.com">Pixeldepo</a>
tag('a', array('href' => 'http://www.pixeldepo.com'), 'Pixeldepo');
tag('a', 'Pixeldepo', array('href' => 'http://www.pixeldepo.com'));
tag('a', 'href="http://www.pixeldepo.com"', 'Pixeldepo');

Функцията array_cut

Едно нещо което е изключително досадно в STRICT режима на PHP, е непрекъснатите проверки isset / empty за това дали в даден масив има даден ключ. Затова създадох array_cut, тя проверява дали в дадения масив го има ключа и ако го има му връща стойността, ако я няма връща $default стройност. Като същевременно ключът се изтрива от оригиналния масив.
Това като се замисля е първата функция която написах за PHP framework-а който използвам ControlDepo 3.

function array_cut(array &$array, $key, $default = null){
    if (!isset($array[$key])){
        return $default;
    }

    $value = $array[$key];
    unset($array[$key]);

    return $value;
}

Тази функция е изключително полезна и може да се използва в редица случаи, ето два примера:

// това може да се напише така:
$name = isset($_POST['name']) ? $_POST['name'] : '[no-name]';
// може да се напише така:
$name = array_cut($_POST, 'name', '[no-name]');

// използване на array_cut за примерна функция за генериране на url-та
function url($options){
    $url = '/' . join('/', array_filter(array(
        array_cut($options, 'controller'),
        array_cut($options, 'action', 'index'),
        array_cut($options, 'id')
    )));

    if ($query = http_build_query($options)){
        $url .= '?' . $query;
    }

    return $url;
}
// използване
// -> /products/view/1
url(array('controller' => 'products', 'action' => 'view', 'id' => 1));

// -> /users/index?page=1
url(array('controller' => 'users', 'page' => 1));

// -> /index?sort=name
url(array('sort' => 'name'));

Преди време си мислех, че в PHP5.3/6 смисълът от функцията ще се намали след като се добавиха ?: и  ifsetor. Но просто ?: не е толкова мощен колкото ми се искаше, а ifsetor няма да го има.

Функцията profile

Докато другите 2 функции ги използвам много (и също така цялото ControlDepo 3 ги ползва). Функцията profile() е просто бърз начин за замерване, докато работя. В действителност тази функция се използва чрез чрез друга моя функция p(), която просто вика profile(), но записва резултата в лога на request-a и така малко по-лесно може да го анализирам резултата:

function profile($scope = '__default__'){
    static $time = array();

    if (isset($time[$scope])){
        return microtime(true) - array_cut($time, $scope, 0);
    }

    $time[$scope] = microtime(true);
}

Тя се ползва просто така:

// имаме 2 нива на profile
profile('test');
sleep(1);

profile();

sleep(1);

echo profile(), "\n";
echo profile('test');

Надявам се тези 3 функции да са полезни на някои и ако някои има идеи как може да се подобри някоя от тях, ще се радвам да го сподели.

4 коментара за "Няколко полезни php функции"

  1. Иван каза:

    (Човек, нещо не мога да пускам коментари лесно. имам чувство, че ми свършва сесията на капчата и като постна гърми. после при връщане към тази страница го няма вече въведенето съдържание.)

    Та.. бях писал за функцията таг.

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

    Може да се добави доп. настройка дали сайта е в HTML или XHTML режим и само затварящите тагове да се затварят по друг начин.

    (после отбелязах приликата с lowPro / Builder за Prototype и попитах дали можеш да нестваш тагове.)

    Допълнително, тази проста функция може да се замени със маааалко по-сложен абстрактен клас. Примерно TagBuilder, който при инициализация проверява за съществуване на някоя стандартна php XML библиотека и ако я има, да я ползва нея вместо да свърза низове. Презюмцията е, че с XML nodes се работи по-бързо от колкото с низове.

    Допълнително класа може да има по един метод за всеки таг.

    Допълнително може да се прави проверка дали тага е само затварящ т.е. се img, hr, br и т.н.

    Допълнително може да се направи някаква проверка за йерархия т.е. кой елемент какво може да съдържа (изисква XML режим).

    И накрая го истанцираш tag = new TagBulder() ;)

    Но както казах, това вече отива към един доста по-сложен клас, а не тази бърза функция ;)

  2. Radoslav Stankov каза:

    Благодаря за коментара (ще проверя дали работят както трябва)

    За HTML или XHTML, просто винаги ползвам XHTML. А и никога не ползвам tag за единични тагове.
    А аргументите са както си искаш, така ги викаш в смисъл което искаш това е 1во и 2ро.

  3. Иван каза:

    За този суич между HTML / XHTML го казвам с оглед на това, че HTML 5 по подразбиране е с HTML синтаксис, а ако искаш да е XHTML, трябва хедъра да е върнат с тип “application/xml+xhtml” (или още няколко), но нито един няма да се разбира от ИЕ 8-. Даже и за ИЕ 8 не съм сигуирен до колко разбира въпросния хедър.

  4. Radoslav Stankov каза:

    И това го има, тъйкато администраитвните модули към проектите ми ги подържам само за Firefox / Safary много се чудех дали да минавам на HTML5 за там.

Какво мислите по въпроса