Korisni PHP saveti i trikovi
PHP je kroz sve ove godine stekao i zadržao status najpopularnijeg programskog jezika za web. Zato nije čudo da je veliki broj web developera odabrao upravo PHP za svoj prvi programski jezik.
U ovom tekstu ćemo vam pokazati neke male trikove i savete koji vam mogu pomoći da lakše rešite neke od problema u svom svakodnevnom radu kao PHP developer.
If and else
Sigurno ste se već mnogo puta susreli sa else
i else if
. Naravno da ovi statement-i imaju svoje mesto u kodu, ali u nekim slučajevima oni su jednostavno suvišni. Evo jednog primera:
function output_gender(bool $user_is_male) {
if ($user_is_male) {
return "User is male";
} else {
return "User is female";
}
}
U ovom slučaju funkcija output_gender
vraća output bazirano na tome da li je po bulovoj vrednostu $user_is_male
istinito (true
) ili ne (false
). Kada se return
koristi u funkciji, svaki kod koji dolazi nakon return
se ignoriše od strane PHP-a. Stoga, ako je $user_is_male
istinito, onda će else
blok biti ignorisan, jer je funkcija već vratila vrednost. Imajući ovo u vidu, možemo da se potpuno rešimo else
bloka na sledeći način:
function output_gender(bool $user_is_male) {
if ($user_is_male) {
return "User is male";
}
return "User is female";
}
If blokovi – manje ili više
Ovaj savet se oslanja na prethodni, ali ide i nešto dalje od toga. U if
/else
, kao i kod prethodnog primera, možete imati situaciju gde jedan od dva bloka ima manje koda od drugog. U tom slučaju je bolje da se prvo pozabavite blokom koji sadrži manje kod. Evo primera:
public function categoryWithPosts($category)
{
$category = Category::find($category);
if ($category) {
$category->posts = $category->posts()->published()->get();
return response(['data' => $category], 200);
} else {
return response(['error' => 'Category not found'], 404);
}
}
Kod iznad proverava kategoriju posta i pokreće uslov u zavisnosti od toga da li je kategorija pronađena ili ne. Ako bismo iskoristili samo savet broj 1, dobili bismo kod kao na primeru ispod:
public function categoryWithPosts($category)
{
$category = Category::find($category);
if ($category) {
$category->posts = $category->posts()->published()->get();
// having any more code here would
// bloat this part of the function
return response(['data' => $category], 200);
}
return response(['error' => 'Category not found'], 404);
}
Ovaj kod je ispravan, ali je jasno uočljivo da je naš veliki blok koda upakovan u vitičaste zagrade {}
. Da je ovaj kod bio mnogo duži, bio bi problem spakovati ceo kod u if
blok. Umesto toga možemo ga napisati kao u primeru ispod:
public function categoryWithPosts($category)
{
$category = Category::find($category);
if (!$category) {
return response(['error' => 'Category not found'], 404);
}
$category->posts = $category->posts()->published()->get();
// we can freely have more code here
// without worrying about the code looking weird
return response(['data' => $category], 200);
}
S obzirom da else
blok ima manje koda, možemo da koristimo negativni statement (!
) da bi ovaj kod bio prvi pokrenut. Drugim rečima, naš if
kod će biti pokrenut ako kategorija nije pronađena. To nam daje više prostora da upravljamo blokom koji sadrži više koda.
Proveravanje višestrukih stringova
Recimo da želimo da otkrijemo da li određena promenljiva jeste ili nije jedna od stringova, očigledno moramo da napišemo gomilu uslovnih statement-a da biste to proverili:
$item = "candy";
switch ($item) {
case 'candy':
return true;
case 'toy':
return true;
default:
return false;
}
// we're not adding break because we're using return
// or
if ($item == 'candy' || $item == 'toy') {
return true;
}
return false;
Ovaj kod vraća false
ako promenljiva item
nije ni candy ni toy. Ovo je naravno potpuno ispravno, ali je previše ponavljanja. Umesto toga možemo da proverimo niz na string koji želimo da pronađemo:
if (in_array($item, ["candy", "toy"])) {
return true;
}
return false;
Ovo može biti i dodatno skraćeno jer in_array
vraća bulovu vrednost:
return in_array($item, ["candy", "toy"]);
Drugim rečima, rekli smo računaru da proveri da li niz sadrži „candy“ ili „toy“ i u zavisnosti od toga da li je pronašao vrati true
, a u suprotnom će vrednost biti false
.
??
??
je verovatno najlakši način za kreiranje inline uslova bez 2 dela. Hajde da pogledamo primer sledećeg koda:
$data = [
"a" => 1,
"b" => 2,
"c" => null,
];
return $data["c"] ? $data["c"] : "No data";
Poslednja linija u ovom kodu proverava da li je ključ c
u $data
istinit i ukoliko nije vraća "No data"
.
Sada možemo da ponovo napišemo ovu liniju koda tako da izgleda ovako:
// ...
return $data["c"] ?? "No data";
U ovom slučaju ??
se ponaša kao II
logički operator.
Rekurzija iznad ponavljanja
U suštini ovo je veoma jednostavno: probajte da koristite rekurziju umesto višestrukih ponavljanja koda. Postoje situacije u kojima ćete neizbežno morati da ponavljate svoj kod i to je sasvim u redu, ali ako se zateknete da ponavljate svoj kod, probajte na primer sa metodom / rekurzijom. Evo jednog primera:
/**
* Returns request data
*
* This methods returns data passed into the request (request or form data).
* This method returns get, post, put patch, delete or raw faw form data or NULL
* if the data isn't found.
*
* @param string|array $params The parameter(s) to return
* @param bool $safeData Sanitize output
*/
Ovaj metod može da prihvati ili niz ili string i u zavisnosti od inputa on će vratiti string ili niz. Rešenje bi bilo da se proveri da li je input niz, da se loop-uje kroz niz da se prihvate stringovi iz niza, a zatim da se fetch-uju podaci vezano za te stringove. To bi onda trebalo da izgleda ovako:
public function get($params, bool $safeData = true)
{
if (is_string($params)) return $this->body($safeData)[$params] ?? null;
$data = [];
foreach ($params as $param) {
$data[$param] = $this->body($safeData)[$params] ?? null;
}
return $data;
}
Verovatno ste primetili da se $
this->body($safeData)[$params] ?? null
ponavlja, ali nije samo to u pitanju. Šta ako bi se prosledio niz koji je ugnježden u drugi niz. Evo zato alternativnog rešenja:
public function get($params, bool $safeData = true)
{
if (is_string($params)) return $this->body($safeData)[$params] ?? null;
$data = [];
foreach ($params as $param) {
$data[$param] = $this->get($param, $safeData); // I called the function again
}
return $data;
}
Na ovaj način smo obezbedili da dok je loop-ovana vrednost string, on neće pokušavati da fetch-uje njegove podatke. Jeste da je u pitanju mali trik u odnosu na prethodni primer, ali je definitivno koristan u nekim situacijama. Ujedno, imajte u vidu da je ova funkcija class scope-ovana, pa iz tog razloga koristimo $this
PHP + HTML
Ovo možemo da koristimo kada želimo da pišemo PHP u našem HTML kodu, ili obrnuto. U tom slučaju pišemo najčešće nešto ovako:
<?php
foreach ($items as $item) {
echo '
<div class="product__card">
<h3>{$item->name}</h3>
</div>
';
}
?>
Iako je ovo sasvim u redu, jasno je da ovde HTML output-ujemo kao string. Što više HTML-a u kodu, to je teže upravljati svim tagovima i pritom voditi računa o svim linijama HTML koda. Postoji jedno zgodno rešenje za rešavanje ovog problema:
<?php foreach ($items as $item): ?>
<div class="product__card">
<h3><?php echo $item->name; ?></h3>
</div>
<?php endforeach; ?>
Ovde je odmah uočljivo na koji način održavamo naše HTML formatiranje i poravnanje. Ovde nije u pitanju neki templating engine, već samo pokušavamo da učinimo kod jednostavnijim pomoću PHP koda. Jedan važna stvar vezano za PHP je način na koji jednu stva možete uraditi na više različitih načina. Evo šta zapravo koristimo u ovom primeru iznad:
foreach (...):
// code
endforeach;
// also works with if
if (...):
// code
endif;
// also
if (...) #one line code
while():
// ...
endwhile;
Pisanje funkcionalnih blokova
Funkcionalni blokovi mogu da se primenjuju u rasponu od složenih funkcionalnosti, do jednostavnih linija koda. Poenta je kreirati taj funkcionalni blok. Ne samo da bismo izbegli ponavljanja, već i da bi smo ubrzali naš workflow i učinili naš kod čitljivijim. Možete napisati jednostavan metod da biste kreirali redirekciju kao na primeru ispod:
function redirectTo($route) {
header("location: $route", true, 302);
Tako, umesto da svuda pišemo header("location: /home", true, 302, ima više smisla da pišemo redirectTo("/home")
. Ovo se odnosi i na 3rd party biblioteke i dugačke procese. Tako na primer možemo da napišemo:
UserNotification::send($user_id, $notification);
Što je očigledno bolje nego pisati gomilu linija svaki put kada korisniku treba da pošaljemo notifikaciju. To bi bio još jedan mali ali koristan savet.
Korišćenje Framework-ova i biblioteka
Treba biti svestan činjenice da korišćenje open-source biblioteka ponekad može da stvori probleme. Pritom ne sugerišemo da ih ne koristite, već da samo budete obazrivi. I jedni i drugi mogu mnogo da pomognu u našem svakodnevnom radu. Ipak, treba biti obazriv i pre korišćenja dobro počitati dokumentaciju i proveriti eventualna upozorenja / iskustva drugih na Github-u.
Ono što je važno napumenuti jeste da pre korišćenja nekog PHP framework-a treba dobro da se upoznate prvo sa PHP-om. Nakon toga odaberite onaj koji vam najviše odgovara i radite sa njim. Postoji nekoliko dobrih izbora:
Laravel – stari znanac pomoću kojeg možete uraditi gotovo sve što poželite u PHP-u
Slim – Rest API framework koji vam daje veću individualnost
Leaf – dobar spoj Laravel-a i Slim-a u jednom
Pored navedenih tu je još dosta dobrih PHP framework-ova.
Korišćenje tipova
Još jedan jednostavan trik. U pitanju je jedan od najređe korišćenih, ali ipak jedna moćna funkcionalnost u PHP-u. Možete pisati function description-e kao u primeru sa rekurzijama, ali to može da postane prilično zahtevan zadatak kada su u pitanju veliki projekti.
Evo jednog primera koji može da pomogne:
function getItem($item) {
// $item is expected to be an array
// for whatever reason
return allItems()[$item[0]];
}
Ako bi neki drugi developer radio na ovom projektu, logično bi pomislio da se uz getItem
metod, za $item
promenljivu logično očekuje da bude string, ali je zapravo funkcija napisana da radi sa nizom. Ono što bi ovde bio problem je da čak i ako biste prosledili string, to ne bi napravilo problem u radu aplikacije.
Sa druge strane, to možemo izbeći korišćenjem sledeće logike:
function getItem(array $item) {
return allItems()[$item[0]];
}
Na ovaj način šta god bude dodato ovde, biće evaluirano po tipu. Takođe možete koristiti metode kao što su is_string
i is_array
, kao na primeru ispod:
function getItem($item) {
if (!is_array($item)) throwErr("item should be array");
return allItems()[$item[0]];
}
Nadamo se da će vam neki od ovih saveta i trikova pomoći u vašem svakodnevnom radu u PHP-u. Da li vi imate neki savet? Možda neku dopunu na naše savete? Pište nam u komentarima.
Bez komentara