¿Es esta una forma adecuada de "carga" vistas en PHP? -- php camp codereview Relacionados El problema

Is this a proper way of “loading” views in PHP?


9
vote

problema

Español

Como ejercicio de aprendizaje, estoy desarrollando mi propio marco PHP. Estoy buscando una forma de "cargar vistas" (un poco como el codeigniter lo hace), sin contaminar mi alcance general.

Me acompañé lo siguiente, básico, ejemplo:

  $data['test'] = 'Hello world';  $str = load_view($data, true); echo $str;  function load_view($data, $store = false) {     extract($data);      ob_start();     include('view.php');      if($store)  return ob_get_clean();     else        ob_end_flush(); }  // End of file   

vise.php
<p><?php echo $test; ?></p>

También podría usar load_view($data) , que emitiría los contenidos de View.php inmediatamente.

Editar: Estoy en su mayoría preocupado por el rendimiento. Como señaló Peter, sé que la función debe ser un método de clase que está separado de la lógica.

Original en ingles

As a learning exercise, I'm developing my own PHP framework. I'm looking for a way to "load views" (kinda like CodeIgniter does it), without polluting my general scope.

I came up with the following, basic, example:

$data['test'] = 'Hello world';  $str = load_view($data, true); echo $str;  function load_view($data, $store = false) {     extract($data);      ob_start();     include('view.php');      if($store)  return ob_get_clean();     else        ob_end_flush(); }  // End of file 

view.php
<p><?php echo $test; ?></p>

I could also use load_view($data), which would output the contents of view.php immediately.

Edit: I'm mostly worried about performance. As Peter pointed out, I'm aware that the function should be a class method that's seperate from the logic.

  

Lista de respuestas

6
 
vote

Estoy de acuerdo en que es un mejor patrón para envolver la lógica de su vista en una clase.

Aquí hay algún código que me quité esta noche: representa la clase más sencilla que podría diseñar que contiene la lógica mínima que necesito en una vista:

  • incluye - capacidad para incluir otras vistas

  • captura: capacidad para capturar fácilmente el contenido dentro de su vista

  • diseños - Capacidad para inyectar datos en una plantilla de diseño reutilizable

  • busca - Habilidad para buscar la salida de vista en lugar de enviarla al búfer de salida

  • Datos - Capacidad para acceder a los datos resultantes una vez que finaliza la vista

[editar] Refactored por conversación en comentarios sobre la aprobación de $ datos por referencia.

view.php

  <?php /**  * Simple view class that supports includes, capturing, and layouts, as well  * as retrieving rendered view content and resulting data.  *  * *NOTE* When a view uses a layout, the output of the view is ignored, as  *        as the view is expected to use capture() to send data to the layout.  *  * @author David Farrell <DavidPFarrell@gmail.com>  */ class View implements ArrayAccess {     /**      * View file to include      * @var string      */     private $file;      /**      * View data      * @var array      */     private $data;      /**      * Layout to include (optional)      * @var string      */     private $layout;      /**      * Constructor      *      * @param string $file file to include      */     public function __construct($file)     {         $this->file = $file;     }      /**      * render Renders the view using the given data      *      * @param array $data      * @return void      */     public function render($data)     {         $this->data = $data;         $this->layout = null;          ob_start();          include ($this->file);          // If we did not set a layout         if (null === $this->layout)         {             // flush view output             ob_end_flush();         }         // We set a layout         else         {             // Ignore view output             ob_end_clean();              // Include the layout             $this->include_file($this->layout);         }     }      /**      * fetch Fetches the view result intead of sending it to the output buffer      *      * @param array $data      * @return string The rendered view content      */     public function fetch($data)     {         ob_start();         $this->render($data);         return ob_get_clean();     }      /**      * get_data Returns the view data      *      * @return array      */     public function get_data()     {         return $this->data;     }      /**      * include_file Used by view to include sub-views      *      * @param string $file      * @return void      */     protected function include_file($file)     {         $v = new View($file);         $v->render($this->data);         $this->data = $v->get_data();     }      /**      * set_layout Used by view to indicate the use of a layout.      *      * If a layout is selected, the normal output of the view wil be      * discarded.  The only way to send data to the layout is via      * capture()      *      * @param string $file      * @return void      */     protected function set_layout($file)     {         $this->layout = $file;     }      /**      * capture Used by view to capture output.      *      * When a view is using a layout (via set_layout()), the only way to pass      * data to the layout is via capture(), but the view can use capture()      * to capture text any time, for any reason, even if the view is not using      * a layout      *      * @return void      */     protected function capture()     {         ob_start();     }      /**      * end_capture Used by view to signal end of a capture().      *      * The content of the capture is stored under $name      *      * @param string $name      * @return void      */     protected function end_capture($name)     {         $this->data[$name] = ob_get_clean();     }      /* ArrayAccess methods */     public function offsetExists($offset)      { return isset($this->data[$offset]); }     public function offsetGet($offset)         { return $this->data[$offset]; }     public function offsetSet($offset, $value) { $this->data[$offset] = $value; }     public function offsetUnset($offset)       { unset($this->data[$offset]); }  }   

run.php

  <?php require "View.php";  $v = new View('view_main_simple.php'); $fetch = $v->fetch(array('message' => 'Hello, world')); print("Fetch result: {$fetch} ");  $v = new View('view_main_complex.php'); $v->render(array('one' => 1, 'two' => 2, 'rows' => array('a','b','c')));  $data = $v->get_data();  print(" "); var_export($data);   

view_main_simple.php

  The message is: <?php echo $this['message'] ?><br/>   

view_main_complex.php

  <?php $this->set_layout('view_layout.php') ?> <?php $this->capture() ?>     one=<?php echo $this['one'] ?><br/>     <?php $this->include_file('view_include.php') ?>     three=<?php echo $this['three'] ?><br/> <?php $this->end_capture('body') ?>   

view_include.php

  two=<?php echo $this['two'] ?><br/> <?php $this['three'] = 3 ?> <ul>     <?php foreach($this['rows'] as $row) { ?>         <li><?php echo $row ?></li>     <?php } ?> </ul>   

view_layout.php

  ScrollViewer0  

Salida del programa

  ScrollViewer1  
 

I agree that its a better pattern to wrap your view logic in a class.

Here is some code I whipped together tonight - It represents the simplest class I could devise that contains the minimum logic that I require in a view:

  • Includes - Ability to include other views

  • Captures - Ability to easily capture content within your view

  • Layouts - Ability to inject data into a re-usable layout template

  • Fetching - Ability to fetch view output instead of sending it to output buffer

  • data - Ability to access the resulting data once the view is finished

[edit] Refactored per conversation in comments regarding passing $data by reference.

View.php

<?php /**  * Simple view class that supports includes, capturing, and layouts, as well  * as retrieving rendered view content and resulting data.  *  * *NOTE* When a view uses a layout, the output of the view is ignored, as  *        as the view is expected to use capture() to send data to the layout.  *  * @author David Farrell <DavidPFarrell@gmail.com>  */ class View implements ArrayAccess {     /**      * View file to include      * @var string      */     private $file;      /**      * View data      * @var array      */     private $data;      /**      * Layout to include (optional)      * @var string      */     private $layout;      /**      * Constructor      *      * @param string $file file to include      */     public function __construct($file)     {         $this->file = $file;     }      /**      * render Renders the view using the given data      *      * @param array $data      * @return void      */     public function render($data)     {         $this->data = $data;         $this->layout = null;          ob_start();          include ($this->file);          // If we did not set a layout         if (null === $this->layout)         {             // flush view output             ob_end_flush();         }         // We set a layout         else         {             // Ignore view output             ob_end_clean();              // Include the layout             $this->include_file($this->layout);         }     }      /**      * fetch Fetches the view result intead of sending it to the output buffer      *      * @param array $data      * @return string The rendered view content      */     public function fetch($data)     {         ob_start();         $this->render($data);         return ob_get_clean();     }      /**      * get_data Returns the view data      *      * @return array      */     public function get_data()     {         return $this->data;     }      /**      * include_file Used by view to include sub-views      *      * @param string $file      * @return void      */     protected function include_file($file)     {         $v = new View($file);         $v->render($this->data);         $this->data = $v->get_data();     }      /**      * set_layout Used by view to indicate the use of a layout.      *      * If a layout is selected, the normal output of the view wil be      * discarded.  The only way to send data to the layout is via      * capture()      *      * @param string $file      * @return void      */     protected function set_layout($file)     {         $this->layout = $file;     }      /**      * capture Used by view to capture output.      *      * When a view is using a layout (via set_layout()), the only way to pass      * data to the layout is via capture(), but the view can use capture()      * to capture text any time, for any reason, even if the view is not using      * a layout      *      * @return void      */     protected function capture()     {         ob_start();     }      /**      * end_capture Used by view to signal end of a capture().      *      * The content of the capture is stored under $name      *      * @param string $name      * @return void      */     protected function end_capture($name)     {         $this->data[$name] = ob_get_clean();     }      /* ArrayAccess methods */     public function offsetExists($offset)      { return isset($this->data[$offset]); }     public function offsetGet($offset)         { return $this->data[$offset]; }     public function offsetSet($offset, $value) { $this->data[$offset] = $value; }     public function offsetUnset($offset)       { unset($this->data[$offset]); }  } 

run.php

<?php require "View.php";  $v = new View('view_main_simple.php'); $fetch = $v->fetch(array('message' => 'Hello, world')); print("Fetch result: {$fetch}\n");  $v = new View('view_main_complex.php'); $v->render(array('one' => 1, 'two' => 2, 'rows' => array('a','b','c')));  $data = $v->get_data();  print("\n"); var_export($data); 

view_main_simple.php

The message is: <?php echo $this['message'] ?><br/> 

view_main_complex.php

<?php $this->set_layout('view_layout.php') ?> <?php $this->capture() ?>     one=<?php echo $this['one'] ?><br/>     <?php $this->include_file('view_include.php') ?>     three=<?php echo $this['three'] ?><br/> <?php $this->end_capture('body') ?> 

view_include.php

two=<?php echo $this['two'] ?><br/> <?php $this['three'] = 3 ?> <ul>     <?php foreach($this['rows'] as $row) { ?>         <li><?php echo $row ?></li>     <?php } ?> </ul> 

view_layout.php

<html> <body> <pre> <?php echo $this['body'] ?> </pre> </body> </html> 

Program Output

Fetch result: The message is: Hello, world<br/>  <html> <body> <pre>     one=1<br/>     two=2<br/> <ul>             <li>a</li>             <li>b</li>             <li>c</li>     </ul>     three=3<br/> </pre> </body> </html>  array (   'one' => 1,   'two' => 2,   'rows' =>    array (     0 => 'a',     1 => 'b',     2 => 'c',   ),   'three' => 3,   'body' => '   one=1<br/>     two=2<br/> <ul>             <li>a</li>             <li>b</li>             <li>c</li>     </ul>     three=3<br/> ', ) 
 
 
       
       
4
 
vote

Una cosa a tener en cuenta es que en MVC, las vistas obtienen sus propios datos del modelo. La vista debe pasarse por un modelo y llamarse métodos para acceder a los datos empresariales. Esto hace que el extracto común ($ datos); Método redundante.

Una visión simplista API puede ser:

$ view = nueva vista ($ Modelo); echo $ vista- & gt; render ();

Si ingresa las plantillas en la ecuación, puede usar $ view = nueva vista ($ modelo, $ plantilla); Pero lo importante a tener en cuenta es que la vista no obtiene datos alimentados por el controlador en MVC. Y aunque muchos marcos de "MVC" web toman este enfoque, esto es técnicamente no MVC, sino PAC.

No tengo suficiente representante para publicar imágenes, pero consulte la imagen de MVC en el artículo Wikipedia. Verá que el controlador nunca interactúa con la vista.

Para obtener más información sobre la arquitectura MVC, consulte: http : //st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html , y http://www.itu.dk/courses/vop/e2005/vop2005e/8_mvc_krasner_and_pope.pdf

 

One thing to note is that in MVC proper, views get their own data from the model. The view should be passed a model and call methods on it to access enterprise data. This makes the common extract($data); method redundant.

A simplistic view API may be:

$view = new View($model); echo $view->render();

If you enter templates into the equation then you could use $view = new View($model, $template); but the important thing to note is that the View does not get fed data by the controller in MVC. And although many web "MVC" frameworks take this approach, this is technically not MVC but PAC.

I don't have enough rep to post images but see the image of MVC on the wikipedia article. You'll see the controller never interacts with the view.

For more information on the MVC architecture see: http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html , and http://www.itu.dk/courses/VOP/E2005/VOP2005E/8_mvc_krasner_and_pope.pdf

 
 
2
 
vote

No veo ningún problema enorme con lo que tiene, específicamente el uso del extracto (). Dudo que notifudes cualquier diferencia en el uso de la memoria o el tiempo de ejecución. Las advertencias que debe tener en cuenta son:

  1. ¿Qué sucede si su matriz de datos $ contiene una tecla "Tienda"? Sobrescribirá su argumento de $ tienda.

  2. Aunque sería inusual para ver los archivos para inicializar las variables, es posible que puedan. En tales casos, tendrás colisiones de nombres variables.

Una gran ventaja que veo al pasar la vista renderizada como una cadena es que puede usar vistas dentro de otras vistas o diseños. En segundo lugar, si desea probar sus controladores, puede afirmar las cosas sobre la vista devuelta. Puede considerar simplemente eliminar el segundo argumento y siempre devolver un valor, haría una variable menos (para escudriñarse) y la dejaría con un tipo de devolución.

 

I don't see any huge problem with what you have - specifically the use of extract(). I doubt you'll notice any difference in either memory use or execution time. The caveats you should be aware of are:

  1. What happens if your $data array contains a key "store"? It will overwrite your $store argument.

  2. Although it would be unusual for view files to initialize variables, it's possible they could. In such cases, you'll have variable name collisions.

A big advantage I see in passing the rendered view back as a string is that you can use views inside other views or layouts. Second, if you wish to test your controllers, you can assert things about the returned view. You might consider simply removing the second argument and always return a value - would make one less variable (to get collided with) and would leave you with one return type.

 
 
 
 
-2
 
vote

No, esta es una forma fea de hacerlo.

Extracto () (cosas PHP4 en 2012/2013?)

El problema con Exract () es que está creando variables Ion a la hiperespacio global (OH DIOS, POR QUÉ) ¿Dónde puede existir (en la localidad también!) Cualquier otra variable y puede tener colisiones de nombre y puede sobrescribir los valores antiguos. Además de esto, está perdiendo el control sobre su código y será difícil de mantener (depurar, solucionar también) y extender.

Load_View ()

No siempre devuelve un valor: en PHP, esto está bien, pero en la programación general es un mal hábito. ¿Hago una cosa en un caso y en otro, hago un total de diferentes cosas en la misma función? ¿Y por qué estoy en una función? ¿Qué tal un método de clase no estático donde lo sé todo en mi pequeño entorno?

Aquí hay un pequeño ejemplo de una idea:

Ver clase

  <?php class View {      private $_file;     public $Data;      public function __construct($viewFile, array $data) {         $this->_file = $viewFile();         $this->Data = $data;     }      public function Render()     {         require $this->_file;     }  }   

Uso

en el archivo de vista:

  <ul> <?php foreach ($this->Data["rows"] as $object) {     echo "<li>";     echo $object->Name;     echo "</li>";} ?> </ul>   

El manejo del búfer de salida nunca es parte de la vista. Tiene que haber algún tipo de tengina que pueda manejar esta cosa. Una cosa una responsabilidad.

¡El problema con el ejemplo es que le está perdiendo una infraestructura de latino entera! En mi expiración de MVC, tengo controlador, controlador de control, ActionInvoker, Resumen ActionResult, ViewResult, muchas otras cosas, lo que es necesario para hacerlo. En mi implementación de IView predeterminada, tengo un modelo "Propiedad" junto a ViewData, puedo mapear mucho a HTML o URL y cualquier otro y luego viene los otros: renderpartial (), Rendersection (), Sección (), Sección ( ), Sección, diseño (); Estos están apuntando a mi implementación actual de IviewEngine, que está manejando todas estas cosas.

 

No this is an ugly way to do it.

extract() (PHP4 stuff in 2012/2013?)

The problem with exract() is that it's creating variables ionto the global hyperspace (oh God, why) where can exist (in localy also!) any other variable and can have name collisions and can overwrite the old values. Beside this you are losing the control over your code and it will be hard to maintain (debug, fix also) and to extend.

load_view()

Not always returns a value: in PHP this is okay but in general programming it's a bad habit. I do one thing in a case and in another one i do a complete different stuff in same function? And why am i in a function? How about a non-static class method where i know everything in my small environment?

Here is a small example of an idea:

View class

<?php class View {      private $_file;     public $Data;      public function __construct($viewFile, array $data) {         $this->_file = $viewFile();         $this->Data = $data;     }      public function Render()     {         require $this->_file;     }  } 

Usage

In the view file:

<ul> <?php foreach ($this->Data["rows"] as $object) {     echo "<li>";     echo $object->Name;     echo "</li>";} ?> </ul> 

The output buffer handling is never part of the view it self. There have to be some kind of ViewEngine which can handle this thing. One thing one responsibility.

The problem with the example is that is's missing a whole lat infrastucture! In my MVC expiriment i have Controller, ControllerBuilder, ActionInvoker, abstract ActionResult, ViewResult a lot of other stuff what is necessary to get thing done. In my default IView implementation i have a Model "property" beside the ViewData, i can map a lot helper like Html or Url and any other and just then comes the others: RenderPartial(), RenderSection(), Section(), SectionStart(), SectionEnd(), Layout(); these are pointing to my current IViewEngine implementation which is handling all these stuff.

 
 
         
         

Relacionados problema

30  Codeigniter Active Record Subqueries  ( Codeigniter active record subqueries ) 
Yo uso CodeIgNiter en el trabajo, y uno de nuestros archivos modelo tuvo muchas subcarías en ella. Originalmente tuve que escribir manualmente cada subconsu...

2  PHP Prueba ISSET e instantánea en un disparo. Posible en php?  ( Php test isset and instantiate in one shot possible in php ) 
¿Cómo mejorar este tipo de redundancia? 'done'8 Quiero evitar repetir $ _bet ['NID'] Ejemplo de uso útil de uso: 'done'9 ...

2  Formulario básico de comentarios de PHP  ( Basic php comment form ) 
Soy un novato de programación. He escrito este simple script PHP para ejecutar un formulario de comentarios muy básico y apreciaría cualquier comentario, espe...

28  Biblioteca PHP AutoOoGer  ( Php autoloader library ) 
Básicamente, había escrito esta clase hace poco tiempo para aliviar la carga automática de nuestras bibliotecas locales. La premisa es que todo se divide po...

41  Conexión de la base de datos en constructor y destructor  ( Database connection in constructor and destructor ) 
Estoy jugando con diferentes maneras de hacer la interacción de la base de datos en PHP, y una de las ideas con las que he estado jugando está conectando a la...

2  PHP - Función para manejar las solicitudes  ( Php function to handle requests ) 
Tengo la siguiente función que maneja las solicitudes. Tiene más de 130 líneas public function run() { $objectRequests = json_decode(file_get_contents(...

-4  Demasiado anidamiento [cerrado]  ( Too much nesting ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...

10  Comparando datos en 2 tablas en diferentes servidores con suma de comprobación  ( Comparing data in 2 tables on different servers with checksum ) 
Así que he tenido un problema en el que necesito comparar datos en 2 tablas diferentes en dos servidores diferentes. Ahora, sé que MySQL admite CHECKSUM TABL...

1  Nombre de la bahía Pirata y MAILER MAILER  ( Pirate bay name and magnet mailer ) 
Entonces, primera vez que trato PHP. Pensé que me gustaría establecer un objetivo para mí, dividirlo en problemas más pequeños y comenzar a andar en Google. A...

4  Consulta para trazar un histograma de calificaciones de canciones  ( Query to plot a histogram of song ratings ) 
Escribí código para trazar una distribución de calificación, que se parece a esto: La función más importante es el stats Función: function stats($so...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos