Ghilimelele din PHP

De mai bine de cinci ani (de când am trecut de hello world în PHP) am fost enervat la culme de… ghilimele. Și de inconsistența numelor de funcții, dar despre asta poate cu altă ocazie.

Așadar, să zicem că avem un string, să-i zicem $world="World!"; și vrem să afișăm Hello World folosind acest string. O soluție ar fi:

echo 'Hello ' . $world;

Este ok? Este. E ceva greșit? Nu este. Păi și atunci, unde e problema? Eh, problema apare atunci când vrei să adaugi… de exmplu niște atribute unui tag HTML. Să zicem:

echo '<input type="' . $input_type . '" class="' . $input_class . " 
  id='" . $input_id . "' . $disabled . $readonly . '/>'; 

Acum, nu știu cum sunteți voi, dar eu deja am amețit de la atâtea ghilimele! Gândește-te doar ce se întâmplă într-un query SQL ceva mai complex!

Sunt două chestii trecute cu vederea de foarte mulți:

  1. Dacă ai un string între ghilimele duble poți introduce o variabilă, iar aceasta va fi parsată;
  2. Atributele tag-urilor HTML pot fi puse și în ghilimele simple (de fapt, majoritatea atributelor – cele care nu conțin spații: class, placeholder etc – pot fi adăugate fără nici un fel de ghilimele!)

Acestea fiind spuse, povestea de mai sus se poate rescrie în felul următor:

echo "<input type='$input_type' class='$input_class' id='$input_id' $disabled $readonly/>";

Deja totul este mult mai ușor de urmărit iar șansele să te pierzi în ghilimele au scăzut dramatic!

Ce fac dacă am atributele într-un array?

Sunt situații în care vrei să afișezi elementul unui array:

$input_attr = array(
  "type"     => "text",
  "class"    => "foo bar",
  "id"       => "input_id",
  "disabled" => "disabled",
  "readonly" => "readonly"
);

(Desigur, array-ul ar putea fi la fel de bine un stdObject, că nu s-ar supăra nimeni)

Soluția? Acolade!

echo "<input type='{input_attr['type']}' class='{input_attr['class']}' 
  id='{input_attr['id']}' {input_attr['disabled']} {input_attr['readonly']}/>";

Toată povestea asta merge nu doar în cazul în care vrei să afișezi ceva ci și în cazul în care definești o variabilă, de exemplu (să revenim la exemplul inițial):

$hello = "Hello {$world}";
echo $hello;

Mai multe detalii poți găsi fix la sursă.

27 Comentarii to “Ghilimelele din PHP”

  1. Asta e motivul pentru care am lasat echo si am trecut la printf :)

  2. 1. de ce ai vrea sa faci asta? nu prea cred ca gasesti situatii cand trebuie sa scuipi kile de html cu echo. de fapt sunt sigur ca nu gasesti asemenea situatii.

    ghilimelele simple sunt mai rapide decat alea duble. cam de 7 ori cica. dar asta nu conteaza, castigul de viteza este neglijabil.
    eu nu inteleg de ce-ai vrea sa scuipi ceva de genu echo “<input ….."? nu-i mai simplu sa scrii <input type="” … />? de ce-ai vrea sa te complici cu un cod greu de citit si greu de mentinut?
    si intr-un string poti sa scrii variabilele fara acolade. “$test[test]” == “{$test[‘test’]} (la exemplu fara acolade renunti la setul de ghilimele simple. la obiecte merge fara acolade.

  3. Staicu Ionuț-Bogdan

    @Semeketh:

    Gândește-te doar ce se întâmplă într-un query SQL ceva mai complex

    Da, știu, poate există PDO sau alte extensii de genul ăsta. Dar poate că eu scriu PHP ocazional și nu vreau/nu am timp să învăț chestii avansate.

    Am dat exemplul cu atributele pentru că a fost oarecum la îndemână. Să înțeleg că ți se pare mai ok să faci:

    <input type="<php echo $type; ?>" />
    

    ?

    si intr-un string poti sa scrii variabilele fara acolade. “$test[test]” == “{$test[‘test’]} (la exemplu fara acolade renunti la setul de ghilimele simple. la obiecte merge fara acolade.

    De la manual citire:

    // This is wrong for the same reason as $foo[bar] is wrong  outside a string.
    // In other words, it will still work, but only because PHP first looks for a
    // constant named foo; an error of level E_NOTICE (undefined constant) will be
    // thrown.
    echo "This is wrong: {$arr[foo][3]}"; 
    

    Cât despre care sunt mai rapide, nu uita că:

    premature optimization is the root of all evil

  4. da, mi se pare mult mai ok. mai lizibil si mai usor de intretinut. si ai de scris mai putin (pe varianta cu short open tag). ti-am spus, nu vad nici o justificare sa scuipi html cu ajutorul php-ului (nu ma refer la template-uri). sa zicem ca exemplul cu inputu-ul e de fapt o functie care genereaza inputuri. dar nici asa n-ar fi ok, ai putea gasi o varianta mai buna. sa zicem cu sprintf.

    cat despre exemplele cu interogari complicate… daca esti dispus sa te manjesti scriind interogarea ai putea face un efort sa folosesti o clasa specializata (sa stii ca alea avansate sunt cele mai usor de folosit). au prostul obicei sa sanitizeze interogarea, lucru care tie o sa-ti scape oricat de atent ai fi.

    // This is wrong for the same reason as $foo[bar] is wrong outside a string.
    // In other words, it will still work, but only because PHP first looks for a
    // constant named foo; an error of level E_NOTICE (undefined constant) will be
    // thrown.

    am testat inainte sa dau exemplu. n-a spus nici psss (e pe e_all).

    premature optimization is the root of all evil

    partial adevarat. multi folosesc asta ca scuza sa scrie cod cu picioarele. si dupa aia se trezesc ca optimizare = delete > start fresh.

    ah, eu ma leg de exemplul cu inputul. care ma ustura la ochi. crede-ma, cand vezi pagini intregi scuipate cu echo incepi sa ai pete pe creier. de obicei folosesc ghilimelele simple, dar daca trebuie sa am o variabila intr-un string atunci trec pe ghilimele duble si folosesc varianta cu acolade, indiferent daca-i vorba de array, variabila simpla sau obiect (foloseam un editor care nu vedea variabila decat daca era intre acolade. si am ramas cu obisnuinta). sau cu (s)printf;

  5. ps: asta e ok

    echo $this->Form->input('call_type', array('options' => $agenda_call_types));
    

    produce ceava de genu

    <div>
    <label>Agenda Call Type</label>
    <select name="agenda_call_type">
    ....
    </select>
    </div>
    
  6. sau asa

    echo "<input type=\"$input_type\" class=\"$input_class\" id=\"$input_id\" $disabled $readonly/>";
  7. @alin, mi-a picat un ochi.

  8. Staicu Ionuț-Bogdan

    @Alin: ce ți-e cu un cârnat de ghilimele, ce ți-e cu un cârnat de slash-uri :D

    @semeketh: ok, poate n-am fost destul de explicit și te văd că ești foarte pornit pe inputul meu :D Nu mă refer neapărat la elementele unui formular sau interogări SQL (deși astea au fost primele exemple care mi-au venit în cap). De ex, folosesc wpml la un site și afișez o listă cu limbile disponibile:

    echo "
    <li{$class}>
      <a href='{$lang['url']}' class='lang {$lang['language_code']}' title='{$lang['native_name']}'>
        <span>{$lang['native_name']}</span>
      </a>
    </li>";
    

    S-ar fi putut scrie altfel? Cu siguranță! Ar fi fost la fel de clar? Meh…

    Cred că ține mai mult de preferințele fiecăruia, la fel cum e și indentarea, spațierea etc. Mi se pare obositor să văd < ?php echo ... ?> sau
    < ?= ...; ?> de patru ori pe un rând.

    Cred că seamănă un pic cu războiul tabs vs spații, acolade pe rând nou vs acolade pe același rând etc :)

    Despre nici o abordare nu se poate spune că e cea corectă sau cea gresită (dintre cea prezentată de mine, cu ghilimele duble & acolade vs cea prezentată de tine, cu echo inline); deși, pentru chestii mărunte utilizarea unei biblioteci separate ar putea fi un pic prea mult (bănuiesc că generatorul de formulare nu este built in în PHP; nu-mi spune că ți se pare ok să încarci un lib doar pentru a genera 2-3 fields sau pentru a face un singur query SQL – ca să rămânem la aceleași exemple).

    Cât despre:

    premature optimization is the root of all evil

    Ai dreptate. Doar că în cazul de față, ce zici tu este „premature micro-optimization”.

  9. Ce pot sa spun dupa +5 ani de cand am inceput sa scriu PHP si umblat prin zeci de stiluri diferite e ca te obisnuiesti cu toate si ajunge sa-ti fie indiferent. Adica nu ajungi sa ai dubii cand trebuie sa scrii cu simple sau duble sau acolade. Si la fel si cu urmaritul, iti dai seama foarte rapid daca una pare in neregula si e in minus/plus.

    Daca pui html in php cel mai curat mi se pare cu {$var}

  10. Cele mai tari faze sunt atunci când ai și niște JS prin cod:

    echo '<a href="#aaa" onclick="javascript: myFunction('asasaa')">WTF?!</a>';
    

    :D (evident îți iasă un ghiveci)

  11. Scuze:

    echo '<a onclick="myFunction('asasaa')">WTF?!</a>';
    
  12. Diferenta intre “$var[test]” si “{$var[‘test’]}” este faptul ca in prima expresie test este considerata constanta si daca nu este deja definita, va fi ok, iti va interpreta $var[‘test’].
    Dar ce te faci daca ‘test’ este deja definita? Cum ar veni

    define('test', 'foo');

    ?
    In acest caz “$var[test]” va fi interpretat ca $var[‘foo’]
    Cat despre metoda de folosire, depinde unde folosesti codul:
    – Daca ai nevoie sa stochezi codul html intr-o variabila, desigur ca se prefera

    $var = "<a href='{$url}'>{$text}</a>";

    – Dar daca poti face direct output, atunci e de preferat

    <a href="<?=$url?>"><?=$text?></a>

    Personal, niciodata nu am folosit

    echo '<a href="{$var}">{$text}</a>'
  13. @Alecs: just, man, tot ce-ai spus.
    @semeketh: exista situatii nenumarate cand trebuie sa scuipi kile de html, depinde pentru ce scrii codul pe care-l scrii. Pentru un website, ai partial dreptate. Dar daca scrii o aplicatie fara sa folosesti un framework care sa te scuteasca de amestecatura asta de cod html cu php, ai nevoie sa tii codul html intr-o variabila php. Ultimul lucru pe care-l vrei e sa faci un mare amestec de html cu php ca sa cauti o saptamana mai tarziu sa-ti vina rau numai pentru ca trebuie sa faci o modificare mica-mica.

  14. Ceva imi spune ca Smarty sau Twig au fost inventate dupa ce programatorii constatau ca le cresc dioptriile din 6 in 6 luni.

  15. cip, de ce trebuie sa tii html-ul intr-o variabila?

    $var = 'world'
    include('template.php');
    

    template.php:

    hello <?=$var;?>
    

    te joci putin cu exemplu de sus intr-o ora ai un scriptulet care sa se ocupe de html. si dupa inca o ora ai posibilitatea sa-ti alegi un layout care sa-l schimbi cand vrea muschiu tau, sa poti include alte fisiere care contin html pur sau alte chestii care sa te ajute sa lucrezi mai repede. si nu tre sa ai un framework in spate ca sa-l folosesti.

  16. @semeketh: Nu trebuie musai sa-l tii intr-o variabila, n-am vrut sa reieasa neaparat asta, mai degraba poti sa-l tii intr-o variabila. E o optiune foarte viabila atunci cand ai ramuri decizionale pe care generezi diferite bucati de cod html. Si asta nu neaparat din perspectiva ghilimelelor, cat din perspectiva mentenantei ulterioare a codului, nu vei sta sa bananai in cod html (care in cazul meu e foarte mult generat) amestecat cu php, ci iti vezi variabila pe fiecare ramura si stii unde sa alterezi codul fara sa crapi jumatate de script.

    In alta ordine de idei, sunt de acord cu ce-ai spus mai sus, dar asta tot nu inlatura problema ghilimelelor si nici nu ma face sa nu mai am nevoie sa generez acel cod html, deci nu lucrez mai repede ci mai organizat, iar in final, cu codul html generat tot intr-o variabila pot sa ajung cu el. Daca vreau asta, daca nu, pot sa evit sa-l tin in variabila. Cu ceea ce ai zis tu mai sus (dealtfel, corect) nevoile raman aceleasi sub alta forma. Chestiile astea vin, pana la urma, dupa cum te-ai obisnuit sau dupa cum ai avut nevoie. Sau ai crezut ca ai nevoie.

    Iar cu frameworkurile, ehe, povesti multe. Am renuntat la ele (ma rog, la unele dintre ele, printre care Prado) de multa vreme. Si, desi vad ca nu se intampla asta, inca astept sa-mi creasca dioptriile :).

  17. ok, poate uneori ai nevoie sa-ti tii outputul intr-o variabila.
    dar… :

    echo "<br/><table border=\"0\" cellspacing=0 cellpading=2>
    				<tr>
    				<th colspan=\"6\" style=\"background-color: #999999;color:#000;\">Credit eCreditor</th>
    				</tr>
    				<tr>
    				<th style=\"background-color: #999999;color:#000\">Perioada creditare" .
    							spatiu(5) . "</th>
    				<th colspan=\"5\" style=\"background-color: #999999;color:#000\">Rata lunara</th>
    				</tr>
    				<tr>
    				<td>12 luni</td>
    				<td><span id=\"ron12\" /></td>
    				<td>RON</td>
    				<td width=\"10\"></td>
    				<td><span id=\"eur12\" /></td>
    				<td>EURO</td>
    				</tr>
    				<tr style=\"background-color: #666666;\">
    				<td>18 luni</td>
    				<td><span id=\"ron18\" /></td>
    				<td>RON</td>
    				<td></td>
    				<td><span id=\"eur18\" /></td>
    				<td>EURO</td>
    				</tr>
    				<tr>
    				<td>24 luni</td>
    				<td><span id=\"ron24\" /></td>
    				<td>RON</td>
    				<td></td>
    				<td><span id=\"eur24\" /></td>
    				<td>EURO</td>
    				</tr>
    				<tr style=\"background-color: #666666;\">
    				<td>36 luni</td>
    				<td><span id=\"ron36\" /></td>
    				<td>RON</td>
    				<td></td>
    				<td><span id=\"eur36\" /></td>
    				<td>EURO</td>
    				</tr>
    				<tr>
    				<td>48 luni</td>
    				<td><span id=\"ron48\" /></td>
    				<td>RON</td>
    				<td></td>
    				<td><span id=\"eur48\" /></td>
    				<td>EURO</td>
    				</tr>
    				<tr style=\"background-color: #666666;\">
    				<td>60 luni</td>
    				<td><span id=\"ron60\" /></td>
    				<td>RON</td>
    				<td></td>
    				<td><span id=\"eur60\" /></td>
    				<td>EURO</td>
    				</tr>
    				</table>
    
    				<script>displayRates($pret_total_tva , $curs_valutar);</script>";
    							echo "</div>";
    							echo "<br/>Aveti cupon?";
    							if($browseru == "opera"){
    									echo spatiu(2) .
    									"<label for=\"cuponda\" >Da <input id=\"cuponda\" onclick=\"if(getElementById('cuponda').selected==true){document.getElementById('cc').style.display='';}else{document.getElementById('cc').style.display='none';}\" type=\"radio\" name=cuponnu /></label>";
    									echo spatiu(5) .
    									"<label for=\"cuponnu\" >Nu </label><input onclick=\"if(getElementById('cuponnu').selected==true){document.getElementById('cc').style.display='none';}else{document.getElementById('cc').style.display='';}\" id=\"cuponnu\" type=\"radio\" name=cuponnu />";
    							}
    							elseif($browseru == "ie"){
    									echo spatiu(2) .
    									"<label for=\"cuponda\" >Da <input id=\"cuponda\" onclick=\"if(getElementById('cuponda').selected==true){document.getElementById('cc').style.display='';}else{document.getElementById('cc').style.display='none';}\" type=\"radio\" name=cuponnu /></label>";
    									echo spatiu(5) .
    									"<label for=\"cuponnu\" >Nu </label><input onclick=\"if(getElementById('cuponnu').selected==true){document.getElementById('cc').style.display='none';}else{document.getElementById('cc').style.display='';}\" id=\"cuponnu\" type=\"radio\" checked name=cuponnu />";
    							}
    							else{
    									echo spatiu(2) .
    									"<label for=\"cuponda\" >Da <input id=\"cuponda\" onclick=\"if(getElementById('cuponda').checked==true){document.getElementById('cc').style.display='';}else{document.getElementById('cc').style.display='none';}\" type=\"radio\" name=cuponnu /></label>";
    									echo spatiu(5) .
    									"<label for=\"cuponnu\" >Nu </label><input onclick=\"if(getElementById('cuponnu').checked==true){document.getElementById('cc').style.display='none';}else{document.getElementById('cc').style.display='';}\" id=\"cuponnu\" type=\"radio\" checked name=cuponnu />";
    							}
    							echo "<span style=\"display:none\" id=\"cc\"><br/>ID CUPON <input type=\"text\" name=\"cupon\"></span>";
    							if($browseru == "ie"){
    									echo "<script>document.getElementById('cuponnu').selected=true;</script>";
    							}
    							elseif($browseru == "opera"){
    									echo "<script>document.getElementById('cuponnu').selected=true;</script>";
    							}
    							else{
    									echo "<script>document.getElementById('cuponnu').checked=true;</script>";
    							}
    							echo "</fieldset>";
    							echo "<br><fieldset style=\"padding:10px;\"><legend class=\"legsel\">INFORMATII (optional)</legend>";
    							$campanie = executa($con, "SELECT * FROM mv_campanii");
    							$ci = 0;
    							echo "<ul type=\"none\">";
    							while($r_campanie = linie($campanie)){
    									$ci++;
    									$cod_campanie = coloana($r_campanie, "cod");
    									$denumire_campanie = coloana($r_campanie, "denumire");
    									echo "<li>$denumire_campanie</li>";
    									echo "<ul>";
    									$detalii_raspuns = executa($con, "SELECT * FROM mv_campanii_raspunsuri WHERE cod_campanie=$cod_campanie");
    									$j = 0;
    									while($r_raspunsuri = linie($detalii_raspuns)){
    											$j++;
    											$cod_raspuns = coloana($r_raspunsuri, "cod");
    											$continut_raspuns = coloana($r_raspunsuri, "continut");
    											echo "<li><label for=\"" . $ci . "add$j\"> $continut_raspuns <input id=\"" . $ci .
    											"add$j\" name=\"campanie$ci\" type=\"radio\" value=$cod_raspuns /></label></li>";
    									}
    									echo "</ul>";
    									echo "<hr>";
    							}
    							echo "</ul>";
    							echo "<input type=\"hidden\" name=\"cate_campanii\" value=\"$i\">";
    							echo "</fieldset>";
    

    codul de mai sus n-are nici o scuza. si de asta-s asa pornit impotriva. si pentru ca ma uit peste codu care-l scriam acu multi ani si ma doare mintea.

  18. Nu prea este necesar să incluzi în echo tot codul html. Codul respectiv nu mai este necesar sa treacă prin PHP, pentru că o să iasă fix în aceeași formă.

    Nu știu dacă ți se pare mai simplu sau mai curat, dar poți încerca:

    <input type="<?php echo $input_type; ?>" class="<?php echo $input_class; ?>" id="<?php echo $input_id; ?>" <?php echo $disabled.$readonly; ?>/>
  19. Staicu Ionuț-Bogdan

    @Alex: ce faci dacă vrei doar să returnezi acel input, nu să-l afișezi?

  20. Pentru texte care se intind pe mai multe randuri, se poate folosi si Heredoc
    Heredoc PHP
    In acest fel se pot folosi ghilimele simple si duble fara nici o problema.

    $str = <<<EOT
    My name is "$name". I am printing some $foo->foo.
    Now, I am printing some {$foo->bar[1]}.
    This should not print a capital 'A': \x41
    EOT;
    
  21. @Ionut pentru return incluzi si html, dar o alternativa la ce ai propus tu poate sa fie:

    return sprintf('<input type="%s" class="%s" id="%s" %s />', $input_type, $input_class, $input_id, $disabled . $readonly);

    iar in cazul unui array:

    return vsprintf('<input type="%s" class="%s" id="%s" %s %s />', $input_attr );
  22. Staicu Ionuț-Bogdan

    @Alex: nu știam de vsprintf. Mulțumesc!
    @Alecs: heredoc mi se pare foarte… nu știu cum și încerc să evit. Pentru că eu sunt tentat să pun o grămadă de cod acolo și înainte să-mi dau seama devine ditamai cârnatul, fără pic de syntax highlight sau code completion :)

  23. OMG, cati scriu codu’ cu picioru’ stang…

    exemplul dat de semeketh trebuie urmat:

    echo $this->Form->input('call_type', array('options' => $agenda_call_types));
  24. @adriean În cazul de față termenul “trebuie” nu are ce să caute în context. Articolul face referire strict la probleme de gust și conține câteva exemple de cod procedural. Nu este specificat nicăieri că se folosește un anumit framework și nici măcar nu a fost specificat în articol că se folosește OOP.

    De ce aș utiliza o clasă pt ceva atât de simplu ? Este ca și cum ai demonta motorul de pe mașina ca să faci o pană.

  25. “Așadar, să zicem că avem un string, să-i zicem $hello=”World!”; și vrem să afișăm Hello World folosind acest string. O soluție ar fi:
    1 echo ‘Hello ‘ . $world;
    Este ok? Este. E ceva greșit? Nu este.”
    Ba da, este. Corect este:
    echo ‘Hello ‘,$hello.
    Output: Hello World!
    ( asa cum este va afisa Undefined variable $world in cale)

  26. Staicu Ionuț-Bogdan

    @Ion: ai dreptate. Am corectat, mulțumesc pentru corectare.

  27. Ma rog, m-am legat si eu de o chestie banala ca doar ti-ar fi aratat notificarea cu pricina. Si cred ca ai putea sterge acea variabila taiata, ca nu face decat sa incurce vizual.

Show trackbacks

Ți-a plăcut articolul? Lasă un comentariu!

You can insert code snippets using BBcode:
[js].[/js] [html].[/html] [php].[/php] [css].[/css]
You can also use some HTML tags:
<blockquote>.</blockquote> <code>.</code> <a href="">.</a> <strong>.</strong> <em>.</em>