PHP определяет область действия для включенного файла
У меня довольно много файлов представления PHP, которые я включал в свои контроллеры с помощью простых операторов include. Все они используют методы, объявленные в классе представления, которые они получают, например, $view->method(); Однако недавно я решил, что было бы лучше, если бы включение также выполнялось этим классом представления. Это, однако, изменяет область включенного файла, так что $view больше не определяется. Вот пример кода:
in someViewFile.php (BOTH siuations)
<html>
<head><title><?php echo $view->getAppTitle(); ?></title>
etc.
OLD SITUATION in controller:
$view = new view;
include('someViewFile.php'); //$view is defined in someViewFile.php
NEW SITUATION in controller:
$view = new view;
$view->show('someViewFile'); //$view is not defined in someViewFile.php
Прямо сейчас я решил обойти проблему, используя это в классе представления:
public function show($file){
$view = &$this;
include($file.".php");
}
Можно ли в любом случае объявить область действия включенного файла или это лучший способ решения проблемы?
Эти примеры грубо упрощены.
7 answers
Вы не можете изменить область действия include(), нет, поэтому ваш метод, вероятно, настолько хорош, насколько это возможно в описываемой вами ситуации. Хотя я бы сам пропустил уродливый амперсанд PHP4-compat.
Вот упрощенный, но функциональный класс представления, который я довольно часто видел и довольно часто использую.
Как вы можете видеть в приведенном ниже коде: вы создаете экземпляр представления с именем файла шаблона.
Клиентский код, возможно, контроллер, может отправлять данные в представление. Эти данные могут быть любого типа, даже если вам нужны другие представления.
Вложенные представления будут автоматически отображаться при отображении родительского представления.
Надеюсь, это поможет.
// simple view class
class View {
protected $filename;
protected $data;
function __construct( $filename ) {
$this->filename = $filename;
}
function escape( $str ) {
return htmlspecialchars( $str ); //for example
}
function __get( $name ) {
if( isset( $this->data[$name] ) {
return $this->data[$name];
}
return false;
}
function __set( $name, $value ) {
$this->data[$name] = $value;
}
function render( $print = true ) {
ob_start();
include( $this->filename );
$rendered = ob_get_clean();
if( $print ) {
echo $rendered;
return;
}
return $rendered;
}
function __toString() {
return $this->render();
}
}
Использование
// usage
$view = new View( 'template.phtml' );
$view->title = 'My Title';
$view->text = 'Some text';
$nav = new View( 'nav.phtml' );
$nav->links = array( 'http://www.google.com' => 'Google', 'http://www.yahoo.com' => 'Yahoo' );
$view->nav = $nav;
echo $view;
В шаблоны
//template.phtml
<html>
<head>
<title><?php echo $this->title ?></title>
</head>
<body>
<?php echo $this->nav ?>
<?php echo $this->escape( $this->text ) ?>
</body>
</html>
//nav.phtml
<?php foreach( $this->links as $url => $link ): ?>
<a href="<?php echo $url ?>"><?php echo $link ?></a>
<?php endforeach ?>
То, что я делаю (я не знаю, насколько это нормально), просто
extract($GLOBALS);
include $view.".php";
Чертовски уверен, что работает
Ура!
Еще более упрощенная версия класса представлений:
Class View {
protected $filename;
function __construct($filename){
$this->filename = $filename;
}
function display(){
global $session; //put global variables here
include Cfg::ROOT . '/views/' . $this->filename;
}
function assign($key, $val){
$this->$key = $val;
}
}
В контроллере:
$view = new View('homepage.php');
$view->assign('page_title',$page_title); //assign all needed variables from controller
$view->display();
В файле шаблона/представления:
echo $this->page_title;
Возможно, это связано с моими настройками php или чем-то еще, но если я включу файл в функцию, этот включенный файл будет иметь только область действия переменных этой функции.
$a = 1; // This variable isn't visible for the included file
function render()
{
$b = 2; // This variable is
include('template.php');
}
// ----------------------------------------
// template.php
<html>
<body>
<?=$a?> // wont show
<?=$b?> // will show
</body>
</html>
Я думаю, что я бы выбрал что-то вроде этого:
function render($template, $variables)
{
extract($variables);
include($template);
}
Использование:
render('templates/mytemplate.php', array(a=>1, b=>2));
Расширяя то, что может предложить Куано:
Сделайте еще один шаг вперед и включите переменные в глобальную область выполнения (которые в противном случае пришлось бы вызывать с помощью global во внутренних компонентах include). Идея заключается в том, что вы хотите, чтобы включение работало так, как если бы оно было включено в вашу основную область приложения или область вашего определения.
Рассмотрим этот класс:
class PHPInclude {
private static $globalsList = array(
'GLOBALS','_SERVER','_GET','_POST','_FILES',
'_REQUEST','_SESSION','_ENV','_COOKIE'
);
public static function phpInclude($file,$variables=array()) {
if ( file_exists($file) ) {
$globs = array();
foreach ( $GLOBALS as $key => $value ) {
if ( !in_array($key,sefl::$globalsList) ) {
array_push($globs,$key);
}
}
foreach ( $globs as $key ) {
global $$key;
}
foreach ( $variables as $variable ) {
global $$variable;
}
unset($globs,$key,$value);
ob_start();
include $file;
return ob_get_clean();
}
return '';
}
}
Используйте его следующим образом:
$foo = 'bar';
function testScope() {
$woo = 'sah';
PHPInclude::phpInclude('file.phtml',array($woo));
}
Пример будет автоматически включать $foo
, так как это в глобальной области, и $woo
добавляется, так как он находится в локальной области.
Я не тестировал $this
как произвольную переменную, но мои чувства паука говорят мне, что это не сработает (предупреждение).
Вы можете отправить get_defined_vars() в качестве параметра функции просмотра. Это создает массив, содержащий все определенные переменные в текущей области. В вашем методе "просмотр" вы вызовете PHP "извлечь" из полученного массива.