Sposoby czytelnego formatowania stringów w PHP z wykorzystaniem funkcji sprintf

Treść dodana: 10 grudnia 2015.

Istnieje wiele różnych metod łączenia i wyświetlania stringów w języku PHP. Najbardziej oczywiste jest standardowe złączenie z wykorzystaniem operatora konkatenacji – poprzez kropkę. Od dawna jednak obserwuję, że sprawia też ono najwięcej problemów początkującym.

Przykładowy zapis krótkiego zapytania, które użytkownik może chcieć wysłać do bazy danych, może przyjąć następującą postać:

$sql = "SELECT `id`, `login`, `data_przystapienia` FROM uzytkownicy AS u 
WHERE id IN ('" . implode("', '", $ids) . "') AND id NOT IN(
SELECT id FROM bany WHERE pole = mysql_real_escape_string("$_POST['pole']".)";

Wygląda jak mały koszmar i zawiera co najmniej kilka błędów. W dodatku zapytanie nie jest jeszcze szczególnie długie, a co jeśli będzie zawierało 5 razy więcej danych? Prześledzenie zapytania i znalezienie w nim źle zamkniętych cudzysłowów, nawiasów i kropek jest męczące oraz zupełnie niepotrzebne (już pomijam fakt wykorzystania zdeprecjonowanego rozszerzenia mysql). Nowoczesnym rozwiązaniem było by użycie PDO z bindowaniem parametrów jednak nie zawsze jest to możliwe w starym kodzie. Z małą pomocą może przyjść nam tutaj funkcja sprintf. Działa ona na podobnej zasadzie, czyli zastępuje pewne zdefiniowane przez użytkownika znaczniki kodem właściwym. Takie zmienne w zmiennej. Nasze nowe zapytanie może mieć postać:

$sql = "SELECT `id`, `login`, `data_przystapienia` FROM uzytkownicy AS u
WHERE id IN (%s) AND id NOT IN(
SELECT id FROM bany WHERE pole = '%s')";

Zniknęły funkcje, pojawiła się konstrukcja %s. Oznacza ona iż w miejscu %s znajduje się wartość traktowana i oznaczona w PHP jako string. Inną popularną wartością jest %d oznaczający liczbę całkowitą (dodatnią lub ujemną, signed integer) lub %f – liczbę zmiennoprzecinkową (float). Pełna lista widoczna jest na stronie dokumentacji.

Funkcja sprintf ma następującą postać:

string sprintf ( string $format [, mixed $args [, mixed $... ]] )

Jako pierwszy argument przyjmuje nasz string który będzie poddany obróbce, oraz dowolną ilość argumentów różnego typu które zastąpią znaczniki. Aby w pełni odwzorować nasze pierwotne zapytanie należy jeszcze podstawić funkcje implode() oraz mysql_real_escape_string():

$nowyString = sprintf($sql,
    implode(',', $ids),
    mysql_real_escape_string($_POST['pole'])
);

Dzięki dużej czytelności kodu ryzyko wystąpienia błędu znacznie spadło. Co więcej, bardzo łatwo jest teraz podstawiać kolejne wartości do zapytania.

Jeżeli porównać powyższy kod do PDO, przedstawiona sytuacja obejmuje znaczniki nienazwane – `?`. PHP Data Objects posiada też znaczniki nazwane, definiowane jako `:nazwa`. Różnica jest taka, iż nazwane możemy wykorzystywać wielokrotnie.

$s = 'Ala %1$s %2$d kota, kot %1$s leniwe usposobienie.';
echo sprintf($s, 'ma', 1);

Po znaku procenta wstawiamy liczbę, odpowiadającą kolejności argumentów przekazanych do funkcji sprintf, następnie znak dolara i znane już oznaczenie typu danych.

Funkcja sprintf posiada również możliwość dopełnienia stringu określonymi znakami do określonej długości, co mogło by się przydać do uzupełnienia pól stało-znakowych w bazie danych. Zainteresowanych odsyłam do dokumentacji.

Oczywiście przykład z bazą danych jest typowy ale funkcja sprintf ma przeróżne zastosowania. Pomaga zawsze tam, gdzie bezpośrednie podstawianie wartości jest mało czytelne. Może to być np. uzupełnianie nazw plików:

sprintf('%s/%s.%s', $folder, $nazwaPliku, $rozszerzenie);

Obsługa wyjątków:

try {
    // blok kodu
} catch (Exception $e) {
    Logger::log('Miał miejsce problem: %s, w pliku %s, linii %d',
        $e->getMessage(), $e->getFile(), $e->getLine()
    );
}

Komentarze

Nie ma jeszcze żadnych komentarzy do wyświetlenia. Może chcesz zostać pierwszą osobą która podzieli się swoją opinią?

Dodaj komentarz

*
Nazwa zostanie wyświetlona wraz z komentarzem. Możesz też utworzyć nowe konto w serwisie, dzięki czemu uzyskasz dodatkową funkcjonalność.
*
Akceptowana jest ograniczona składnia Textile. Wszystkie tagi HTML zostaną usunięte.