Domanda

Panoramica

Verso la fine del 2009, ho scritto un semplice sistema di template per PHP/HTML da utilizzare internamente dai nostri designer per siti web di tipo brochure.L'obiettivo del sistema è consentire la creazione di modelli in HTML altrimenti puro tramite tag personalizzati elaborati da PHP.Ad esempio, una pagina basata su modello potrebbe assomigliare a questa:

<tt:Page template="templates/main.html">
  <tt:Content name="leftColumn">
    <p> blah blah </p>
    ...
  </tt:Content>
  <tt:Content name="rightColumn">
    <p> blah blah </p>
    ...
  </tt:Content>
</tt:Page>

Il modello stesso potrebbe assomigliare a questo:

<html>
  <head>...</head>
  <body>
    <div style="float:left; width:45%">
      <tt:Container name="leftColumn" />
    </div>
    <div style="width:45%">
      <tt:Container name="rightColumn" />
    </div>
  </body>
</html>

Oltre ai tag Pagina e Contenuto/Contenitore, ci sono alcuni altri tag inclusi nel core per cose come il controllo del flusso, l'iterazione su una raccolta, l'output di valori dinamici, ecc.Il framework è progettato in modo che sia molto semplice aggiungere il proprio set di tag registrati con un altro prefisso e spazio dei nomi.

Tag personalizzati in PHP

Come analizziamo questi tag personalizzati?Poiché non esiste alcuna garanzia che il file HTML sia XML ben formato, soluzioni come XSLT/XPATH non saranno affidabili.Utilizziamo invece una regex per cercare tag con prefissi registrati e sostituirli con codice PHP.Il codice PHP è un design basato su stack...quando si incontra un tag di apertura, un oggetto che rappresenta il tag viene creato inserito nello stack e la sua "funzione di inizializzazione" (se presente) viene eseguita.Ogni volta che viene incontrato un tag di chiusura registrato, l'oggetto più recente viene estratto dallo stack e viene eseguita la sua "funzione di rendering".

Quindi, dopo che il framework ha sostituito i tag di template con PHP, la nostra pagina di esempio potrebbe assomigliare a questa (in realtà è un po' più brutta):

<?php $tags->push('tt', 'Page', array('template'=>'templates/main.html')); ?>
  <?php $tags->push('tt', 'Content', array('name'=>'leftColumn')); ?>
    <p> blah blah </p>
    ...
  <?php $tags->pop(); ?>
  <?php $tags->push('tt', 'Content', array('name'=>'rightColumn')); ?>
    <p> blah blah </p>
    ...
  <?php $tags->pop(); ?>
<?php $tags->pop(); ?>

Il buono, il cattivo e eval

Ora, come eseguire il nostro codice PHP appena generato?Mi vengono in mente alcune opzioni qui.Il più semplice è semplicemente eval la stringa, e funziona abbastanza bene.Tuttavia, qualsiasi programmatore ti dirà "eval è malvagio, non usarlo..." quindi la domanda è: c'è qualcosa di più appropriato di eval che possiamo usare qui?

Ho preso in considerazione l'utilizzo di un file temporaneo o memorizzato nella cache, utilizzando php:// flussi di output, ecc., ma per quanto posso vedere questi non offrono alcun vantaggio reale rispetto a eval.La memorizzazione nella cache potrebbe velocizzare le cose, ma in pratica tutti i siti che abbiamo su questa cosa sono già incredibilmente veloci, quindi non vedo la necessità di ottimizzare la velocità a questo punto.

Domande

Per ciascuna delle cose in questo elenco:è una buona idea?Riesci a pensare a un'alternativa migliore?

  • l'intera idea in generale (tag personalizzati per html/php)
  • convertire i tag in codice php invece di elaborarli direttamente
  • l’approccio basato sullo stack
  • l'impiego di eval (o simili)

Grazie per la lettura e TIA per qualsiasi consiglio.:)

È stato utile?

Soluzione

Vorrei sostenere un approccio diverso.Invece di generare codice PHP in modo dinamico e poi cercare di capire come eseguirlo in modo sicuro, eseguilo direttamente quando incontri i tag.Puoi elabora l'intero blocco di HTML in un unico passaggio e gestisci ogni tag man mano che lo incontri subito.

Scrivi un ciclo che cerchi i tag.La sua struttura di base sarà simile a questa:

  1. Cerca un tag personalizzato, che trovi in ​​posizione N.
  2. Tutto prima della posizione N deve essere un semplice HTML, quindi salvalo per l'elaborazione o visualizzalo immediatamente (se non hai tag sul tuo file $tags stack probabilmente non è necessario salvarlo da nessuna parte).
  3. Esegui il codice appropriato per il tag.Invece di generare codice che chiama $tags->push, chiama soltanto $tags->push direttamente.
  4. Torna al passaggio 1.

Con questo approccio chiami direttamente solo le funzioni PHP, non costruisci mai il codice PHP al volo per poi eseguirlo in seguito.Il bisogno di eval è andato.

Avrai fondamentalmente due casi per il passaggio n. 3.Quando incontri un tag di apertura, eseguirai un'operazione immediata push.Successivamente, quando premi il tag di chiusura, puoi fare a pop e poi gestisci il tag nel modo appropriato, ora che hai elaborato l'intero contenuto dell'elemento personalizzato.

È anche più efficiente elaborare l'HTML in questo modo.Effettuare ricerche e sostituzioni multiple su una stringa HTML lunga è inefficiente poiché ogni ricerca e ogni sostituzione è O(N) sulla lunghezza della corda.Ciò significa che stai scansionando ripetutamente la stringa più e più volte e ogni volta che esegui una sostituzione devi generare stringhe completamente nuove di lunghezza simile.Se disponi di 20 KB di HTML, ogni sostituzione implica la ricerca in quei 20 KB e la creazione successiva di una nuova stringa da 20 KB.

Altri suggerimenti

Ho postato un'altra risposta perché è radicalmente diverso dal primo, che potrebbe anche essere prezioso.

In sostanza, questa domanda sta chiedendo come eseguire il codice PHP con Regex.Potrebbe non sembrare così ovvio, ma questo è ciò che la Valta ha intenzione di realizzare.

Con ciò detto, invece di fare un passaggio di preg_replace e poi fare una valutazione, è possibile utilizzare la funzione PREG_REPLACE_CALLBACK di PHP per eseguire un pezzo di codice quando è abbinato.

Vedi qui per come funziona la funzione: http://us.php.net/manual/en/function.preg-replace-callback.php

Sì, invece di Eval, puoi fare ciò che lo sviluppo di zend e altri importanti framework, utilizzare il buffering di uscita:

ob_start();
include($template_file); //has some HTML and output generating PHP
$result = ob_get_contents();
ob_end_clean();
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top