PHP определяет область для включенного файла

У меня довольно много файлов представлений PHP, которые я использовал для включения в свои контроллеры с помощью простых операторов включения. Все они используют методы, объявленные в классе представления, которые они получают как $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");
}

Можно ли как-то объявить область действия включенного файла или это лучший способ решить проблему?

Эти примеры очень упрощены.


person Pim Jager    schedule 09.02.2009    source источник


Ответы (7)


Вы не можете изменить область включения include(), нет, поэтому ваш метод, вероятно, настолько хорош, насколько это возможно в описываемой вами ситуации. Хотя я бы сам пропустил уродливый амперсанд, совместимый с PHP4.

person chaos    schedule 09.02.2009

Вот упрощенный, но функциональный класс представления, который я видел довольно много и довольно часто использую.
Как вы можете видеть в приведенном ниже коде: вы создаете экземпляр представления с именем файла файла шаблона.
Клиентский код, возможно, контроллер, может отправлять данные в представление. Эти данные могут быть любого типа, даже если вам нужны другие представления.
Вложенные представления будут автоматически отображаться при отображении родителя.
Надеюсь, это поможет.

// 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 ?>
person meouw    schedule 09.02.2009
comment
Я думаю, что есть крошечная опечатка, где написано имя фильма? - person noio; 28.10.2010
comment
Действительно, член и его использование — это filname, где назначение — filename. Я пытался отредактировать это, но для редактирования требуется 6 символов изменения. закатить глаза - person Travis Watson; 25.02.2013
comment
@meouw Большое спасибо! У меня был обратный поток мыслей о шаблонах. Я могу использовать его для своего проекта без каких-либо фреймворков. - person Davuz; 12.03.2015
comment
Упростил класс представления еще ниже, буду признателен за отзывы. - person Andrew; 02.04.2015
comment
Вам нужно 2 закрыть, если видите эту строку if( isset( $this->data[$name] ) { - person Walter A. Jablonowski; 01.06.2019

Что я делаю (не знаю, насколько это нормально) просто

extract($GLOBALS);
include $view.".php";

Конечно, черт возьми, работает

Ваше здоровье!

person Pedro    schedule 20.10.2010

Еще более упрощенная версия класса View:

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;
person Andrew    schedule 02.04.2015

Возможно, это связано с моими 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));
person quano    schedule 15.02.2011

Расширяя возможности Quano:

Сделайте еще один шаг вперед и включите переменные в глобальную область выполнения (в противном случае их пришлось бы вызывать с помощью 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 как произвольную переменную, но мое паучье чутье подсказывает мне, что она победила не работает (предупреждение).

person zamnuts    schedule 15.02.2013
comment
черт возьми, ответ находится по адресу stackoverflow. ком/вопросы/2211877/ - person zamnuts; 15.02.2013

Я нашел отличное решение. Просто создайте анонимную функцию и вызовите ее. Только для PHP 7+.

$arg1=1;
call_user_func(function()use($arg1,$arg2,...){
 $values=$arg1+$arg2;
 // $values is limited in scope inside this function
}

Например:

$values='HEY!';

//included code
$arg1=1;
$arg2=2;
call_user_func(function()use($arg1,$arg2,...){
 $values=$arg1+$arg2;
 // $values is limited in scope inside this function
}

echo $values;
// echos HEY!
person Maciek Semik    schedule 18.11.2018