Začalo mi vadit, že jsem si musel pamatovat všechny ty speciální funkce pro práci s řetězci a zároveň, že nepodporují kódování UTF-8. Co si budeme povídat, člověk občas zapomene použít mb_ variantu. Proto jsem se nechal inspirovat třídou String v Javě a pokusil se implementovat něco podobného v PHP. Chtěl jsem vytvořit něco, co se bude používat jako standartní řetězce v PHP s přidanou objektovou hodnotou.
Druhá moje myšlenka byla, aby se třída dala instancovat, ale zároveň šla používat i staticky. Tady jsem trochu narazil a byl jsem nakonec nucen udělat třídy dvě. Pokud zavolám nestatickou metodu staticky, vyhodí PHP (alespoň verze 5.3) strict vyjímku. Statickou funkci sice lze z instancované třídy zavolat, ale docela logicky se jí nepředá kontext třídy. Vše jsem chtěl vyřešit pomocí magických funkcí Nakonec jsem využil magických funkcí __call
a __callStatic
, ale nakonec jsem od toho upustil. Chtěl jsem, aby mi IDE napovídalo všechny použitelné metody a takhle bych o tuto vlastnost přišel. Takže nakonec vznikla třída StringInstance
a statická třída String
. Přitom String není pouhou kopií StringInstance, ale jsou v ní pouze staticky využitelné funkce.__call
a __callStatic
. U tohoto řešení mi nejvíc vadilo, že by mi IDE nenapovídalo při psaní kódu, ale využil jsem phpdoc anotaci @method
. Bohužel zde nelze rozlišit statické volání metody od volání metody na instanci třídy. Prozatím nevím jak to vyřešit a tak si musím pamatovat, že statické metody vždy jako svůj první parametr potřebují řetězec, se kterým se bude pracovat a jako volitelný parametr většina z nich přijímá na posledním místě kódování, které je defaultně UTF-8.
Podívejme se teď na využití třídy String. Když chceme vytvořit nový řetězec, použijeme:
$string = new String("Testovací řetězec");
nebo jednodušší:
$string = string("Testovací řetězec");
Konstruktor třídy String
má dva parametry. První povinný je samotný řetězec a druhý nepovinný je kódování. Zadat ho musíte pouze pokud je jiné než UTF-8.
Od teď už s proměnou $string
pracujeme jako s obyčejným řetězcem. Můžeme ho vypisovat, porovnávat (z pochopitelných důvodů pouze pomocí == a ne pomocí ===) a vůbec s ním dělat vše, co s normálním řetězcem.
Teď se ovšem podívejme na onu přidanou hodnotu, kterou jsem zmiňoval na začátku. Většina funkcí je převzata z Javové třídy String a i použití je obdobné. Podívejme se na příkad:
echo $string->length(); // Vypíše délku řetězce echo $string->toUpperCase()->substring(2, 4); // Vypíše ST if($string->startsWith('Test')) { echo "Řetězec začíná na Test..."; }
Nebudu zde vypisovat všechny možné funkce, které můžete použít, najdete je popsané přímo ve třídě. Vypíchnu ještě dvě vlastnosti. Třída implementuje rozhraní Iterator
a ArrayAccess
, proto můžete používat i následující konstrukce:
// Procházení řetězce pomocí foreach foreach($string as $position => $char) { echo $char . " at " . $position . "\n"; } // Práce s řetězcem jako s polem echo $string[5]; // Vypíše v $string[5] = 'X'; // Změní pátý znak na X unset($string[5]); // Vypustí pátý znak z řetězce
Poslední funkce, na kterou bych rád upozornil je encode. Pokud ji zavoláte bez parametrů, vrátí použité kódování. Pokud jí předáte nové kódování, vrátí String
v novém kódování.
Statická třída String
, funguje na podobném principu, akorát jako první parametr přebírá vždy řetězec, na který se má funkce aplikovat a jako poslední většinou použité kódování, které je opět potřeba zadat pouze pokud se liší od UTF-8.
echo String::length("Test..."); // Vypíše délku řetězce echo String::toUpperCase("tohle bude velké"); if(String::startsWith("Testovací string...", 'Test')) { echo "Řetězec začíná na Test..."; }
Třída implementuje fluent interface. Takže je možné používat i následující kontrukce:
echo $string->substring(2)->toLowerCase(); echo String::substring("jejda, tohle bude velké", 7)->toLowerCase();