2013-12-15 54 views
9

Sto facendo un experiment, an html preprocessor come SLIM o Jade.Il tag di chiusura PHP elimina il feed di riga

Questo è il codice PHP che sembra giusto:

nav 
    ul id: "test" 
    li 
     @<?= $Var; ?> 
    li 
     @About 
    li 
     @Contact 

Questa è la atteso pre-elaborati html (sì, $ var == "Test"):

nav 
    ul id: "test" 
    li 
     @Test 
    li 
     @About 
    li 
     @Contact 

Tuttavia, nel browser viene visualizzato il testo errato come prefisso html:

nav 
    ul id: "test" 
    li 
     @Test li 
     @About 
    li 
     @Contact 

Infine, ci sono due modi per renderlo corretto.

  1. Aggiungendo la linea di rottura manualmente:

    nav 
        ul id: "test" 
        li 
         @<?= $Var . "\n"; ?> 
        li 
        @About 
        li 
        @Contact 
    
  2. Scrivendo uno spazio dopo il tag di chiusura PHP (??).

Perché è il primo caso, <?= $Var; ?>, ignorando l'avanzamento riga dopo il tag PHP di chiusura? Non ho potuto trovare nulla da quando Google ha portato troppi risultati sul perché dovresti ignorare il tag di chiusura per ogni ricerca che ho fatto e non quello che volevo trovare.

+1

Ho appena notato questo stesso problema quando provavo ad emettere variabili alla fine di molte righe all'interno di tag '

' HTML usando ''. Avevo bisogno di aggiungere un'interruzione di riga aggiuntiva dopo ognuna di queste per mantenere il testo uscita nel formato corretto. Non mi piace molto questo comportamento, anche se riesco a capire perché questo potrebbe essere stato aggiunto per prevenire un ulteriore output di interruzione di riga alla fine del file quando il file termina in '?>' (e potrebbe essere un file incluso che non dovrebbe produrre nulla). –
                        
                            
    Haprog
                                
                            
                        
                    

risposta

10

Aggiornamento:
Guardando lo src scanner lingua Zend, sembrerebbe che il mio "sospetto" era corretta: il token T_CLOSE_TAG sembrerebbe contenere possibilmente un char a capo. Cosa c'è di più, sarebbe anche sembrare che una chiusura e virgola per l'ultima istruzione in uno script che contiene un tag di chiusura è opzionale ...

<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? { 
    ZVAL_STRINGL(zendlval, yytext, yyleng, 0); /* no copying - intentional */ 
    BEGIN(INITIAL); 
    return T_CLOSE_TAG; /* implicit ';' at php-end tag */ 
} 

Basta guardare per T_CLOSE_TAG in the zend_language_scanner.c and zend_language_scanner.l files here


Al momento sto verificando la sorgente del motore Zend, ma suppongo che, dato che l'ultimo char (s) del codice che hai postato sia, semplicemente, il tag di chiusura (?>), è PHP che sta generando l'output. Visto che non stai dicendo a PHP di produrre un line-feed, è ovvio che PHP non aggiungerà una nuova riga a ciò che stai facendo eco.
Il carattere di riga che segue il tag di chiusura è, ovviamente, ignorato da PHP, ma per qualche ragione, PHP sembra effettivamente consumare quel feed di riga. Sto guardando il codice C che analizza il tuo script PHP, ma penso che potrebbe usare le nuove linee, spazi bianchi, punti e virgola della virgola e tutto ciò come token per inserire l'input nei nodi.
Visto che il tag di chiusura ?> è un token bona-fide e parte della grammatica PHP, potrebbe essere che questo è il punto in cui il line-feed viene effettivamente utilizzato dal motore e perché non fa parte dell'output.

Aggiungendo uno spazio dopo il tag di chiusura, lo spazio potrebbe essere consumato, ma la nuova riga non lo è, quindi potrebbe essere il motivo per cui si sta ancora visualizzando l'alimentazione di riga.
Ho anche provato ad aggiungere 2 avanzamenti di riga a qualche codice di test, e in effetti: l'uscita ha mostrato solo 1 nuova linea:

foo: 
    <?= $bar; ?> 

    foobar 

uscita:

foo: 
    bar 
    foobar 

così sembrerebbe che i miei sospetti potrebbe trattenere l'acqua

Tuttavia, tutto sommato, per evitare di voler hackerare la fonte del motore Zend, aggiungere manualmente l'avanzamento di riga non è un gran che. In effetti, è un buon modo per garantire che i feed di linea corretti siano stati generati:
Supponiamo che tu abbia scritto del codice, su un sistema * NICE sano, dove gli line-feed sono, a tutti gli effetti rappresentati dalla fuga \n sequenza, aggiungendo che char manualmente potrebbe non produrre l'output desiderato su, ad esempio, un sistema Windows (che utilizza \r\n), i sistemi Apple usano \r ...
PHP ha una costante per garantire che stai sfornare i feed di riga corretti , a seconda della piattaforma su cui è in esecuzione il codice: PHP_EOL. Perché non utilizzare tale:

<?= $bar, PHP_EOL; ?> 

Nel caso in cui vi state chiedendo: sì, che è $barvirgolaPHP_EOL che vedete lì. Perché? Pensa a echo o <?= come a COUT di C++, è un costrutto che spinge semplicemente qualunque cosa tu stia proiettando sul flusso di output, che sia una stringa concatenata o solo un elenco di variabili separate da virgole: a cui non importa .

Ora, la seguente sezione della mia risposta sta andando leggermente fuori tema, ma è solo qualcosa di così di base, e ovvio, eppure molte persone sono così inconsapevoli di ciò, che non posso resistere alla tentazione di spiegare una o due cose sulla concatenazione delle stringhe.
PHP, e la maggior parte delle lingue che conosco, non si preoccupa di quanti vars/vals deve inviare al flusso di output. È per quello che è. PHP, e ancora: la maggior parte delle lingue, fa cura della concatenazione di stringhe: una stringa è una sorta di valore costante. Non puoi semplicemente allungare una corda quando l'umore ti porta. Una serie di caratteri deve essere archiviata nella memoria, memoria che deve essere allocata per contenere una stringa più lunga.Ciò che la concatenazione fa in modo efficace (migliore dei casi), è questo: lunghezza

  • calcolo di string1 e string2
  • allocare la memoria aggiuntiva richiesta per concat stringa2 sulla stringa 1
  • copia stringa di 2 a quella nuova (extra) memoria allocata

considerando che, in molti casi, ciò che in realtà accade è:

  • bozzetto lunghezze ute di entrambe le stringhe
  • allocare memoria, necessari per concat entrambe le stringhe
  • copia sia stringhe a tale blocco di memoria appena allocata
  • assegnare il nuovo puntatore a qualunque esigenze variabili assegnando
  • liberare qualsiasi memoria che isn' t fa riferimento più

Un esempio del primo caso:

$str1 = 'I am string constant 1'; 
$str2 = ' And I\'ll be concatenated'; 
$str1 .= $str2; 

Could tradurre al seguente codice C:

char *str1, *str2; 
//allocate mem for both strings, assign them their vals 
str1 = realloc(str1,(strlen(str1) + strlen(str2)+1));//re-allocate mem for str1 
strncat(str1, str2, strlen(str2);//concatenate str2 onto str1 

Tuttavia, semplicemente facendo questo:

$str3 = $str1 . $str2; 

cosa si sta effettivamente facendo è:

char *str3 = malloc((strlen(str1) + strlen(str2) + 1)*sizeof(char)); 
strcpy(str3, str1);//copy first string to newly allocated memory 
strcat(str3, str2);//concatenate second string... 

E come se che weren Basta, pensa che cosa questo codice implica:

$str1 = $str2 . $str1; 

Sì, abbastanza sicuro:

char *str3 = malloc((strlen(str1) + strlen(str2) + 1)*sizeof(char)); 
strcpy(str3, str2);//copy seconds string to start of new string 
strcat(str3, str1);//add first string at the end 
free(str1);//free memory associated with first string, because we're reassigning it 
str1 = str3;//set str1 to point to the new block of memory 

Ora non ho ancora avuto la possibilità di incubi reali concatenazione ancora (non preoccupatevi, non sto andando o). Cose come $foo = 'I ' . ' am '. 'The'. ' ' .$result.' of some'.1.' with a dot'.' fetish';. Guardalo, ci sono delle variabili lì dentro, che potrebbero essere qualsiasi cosa (matrici, oggetti, stringhe huuuge ..., c'è anche un intero lì dentro ... sostituisci i punti con una virgola e spingendola al costrutto echo è così tanto più facile che iniziare a contemplare di scrivere il codice necessario per concatenare correttamente tutti questi valori insieme ...
Scusate per esservi allontanati leggermente, ma visto che questo è, IMO, così semplice, mi sento come se tutti dovessero essere consapevoli di questo ...

+0

Vorrei poterlo revocare più di una volta. Sto già usando una funzione 'normalize()' per convertire tutti i feed di riga in modo che probabilmente non sia un problema. A proposito del newline consumato, potrei dover cambiare il titolo.Tuttavia, cambia l'ipotesi di AFAIK di tutti, dal momento che uno spazio singolo o un singolo feed di riga non inviano apparentemente alcuna intestazione. Infine, mentre so solo quello che ho imparato in un corso base di C, ho capito completamente la tua spiegazione sulla concatenazione. Tuttavia, ho assunto che in eco PHP fosse "abbastanza intelligente" da non allocare alcuna variabile extra. Grazie per l'ottima risposta. –

+1

@FranciscoPresencia: felice di aiutare ... Non intendo questo in modo negativo, ma _assuming' echo' è abbastanza intelligente_ non è un'opzione: 'echo' può solo echo espressioni che sono state valutate in un singolo valore : 'echo 1 + 1;' non fa eco '1 + 1', fa eco' 2'. Allo stesso modo per una stringa concatenata: la concatenazione deve avere una cardinalità più alta, perché potresti fare eco a matrici o oggetti che implementano un metodo '__toString', che deve essere chiamato prima di echeggiare qualsiasi cosa (avvisi di problemi, avvisi ... tutto ciò che serve precedenza su un 'eco') ... –

+0

Ok, quindi da ora in poi, ogni volta che avrò bisogno di echo una concatenazione, lo farò invece come hai fatto notare, 'echo $ str1, $ str2;'. Ho persino trovato [alcune metriche] (http://www.electrictoolbox.com/php-echo-commas-vs-concatenation/). –