PHP 中变量变量的类和对象范围


Class & Object Scope for Variable Variables in PHP

问题 1) 为什么变量/变量$this->$templateparse_and_return()不可见,第 42-50 行,但对$this->fetch可见,第 456-472 行。我认为parse_and_return$this->fetch属于同一个对象,因此$this->$template应该对两个函数都可见。
问题 2) 在哪里初始化$this->$template

bar.tpl 和 foo.tpl 是单独的文件

    <!-- bar.tpl -->
    <HTML>
    <HEAD><TITLE>Feature world - {PAGETITLE}</TITLE></HEAD>
    <BODY BGCOLOR=BLACK TEXT=WHITE>
    <H1>{PAGETITLE}</H1>
    {PAGECONTENT}
    </BODY>
    </HTML> 
    -->
    <!--
    foo.tpl 
    This does not do anything obvious. Please look at {NAME}.
    demo.php3
    -->

索引.php文件

<?php
include "FastTemplate.php";
$tpl = new FastTemplate(".");
$tpl->define(array(foo => "foo.tpl", bar => "bar.tpl"));
$tpl->assign(NAME, "me");
$tpl->assign(PAGETITLE, "Welcome!");

$tpl->parse(PAGECONTENT, "foo"); 
echo $tpl->parse_and_return("bar");
?>

快速模板类/快速模板.php文件

        <?php
        class FastTemplate {
                var $start;
                var $ERROR = "";
                var $LAST = "";
                var $ROOT = "";
                var $FILELIST = array ( );
                var $PARSEVARS = array ( );
                var $LOADED = array ( );
                var $HANDLE = array ( );
                var $UPDT_TIME = '60';
                var $COMMENTS_START = "{*";
                var $COMMENTS_END = "*}";
                var $PATTERN_VARS_VARIABLE = array ( );
                var $PATTERN_VARS_DEFINE = array ( );
                FUNCTION FastTemplate($pathToTemplates = "") {
                    if (! empty ( $pathToTemplates )) {
                         $this->set_root ( $pathToTemplates );
                    }
                    $this->start = $this->utime (); 
                } 
                FUNCTION parse_and_return($tpl_name) {
                    $HREF = 'TPL';
                    $this->parse ( $HREF, $tpl_name );
                    $result = trim ( $this->fetch ( $HREF ) );
                    $this->clear_href ( $HREF );
                    RETURN $result;
                }
                FUNCTION set_root($root) {
                    $trailer = substr ( $root, - 1 );
                         if ((ord ( $trailer )) != 47) {
                             $root = "$root" . chr ( 47 );
                         }
                         if (is_dir ( $root )) {
                             $this->ROOT = $root;
                         } else {
                             $this->ROOT = "";
                             $this->error ( "dir [$root] is not a directory" );
                         }
                } 
                FUNCTION get_root() {
                    RETURN $this->ROOT;
                } 
                FUNCTION utime() {
                    $time = explode ( " ", microtime () );
                    $usec = ( double ) $time [0];
                    $sec = ( double ) $time [1];
                    RETURN $sec + $usec;
                } 
                FUNCTION get_template($template) {
                    if (empty ( $this->ROOT )) {
                     $this->error ( "Root not valid.", 1 );
                     RETURN FALSE;
                    }
                    if (empty ( $template )) {
                     $this->error ( "Template name is empty.", 1 );
                     RETURN FALSE;
                    };
                    $filename = "$this->ROOT" . "$template";
                    $contents = ((function_exists ( 'file_get_contents' ))) ? file_get_contents ( $filename ) : implode ( "'n", file ( $filename ) );
                     RETURN trim ( $contents );
                } 
                FUNCTION parseParamString($string) {
                            $matches=array();
                            if (preg_match_all ( '/'{([a-z0-9_]+)'}/i', $string, $matches )) {
                                    FOR($i = 0; $i < count ( $matches [0] ); $i ++) {
                                            $string = str_replace ( $matches [0] [$i], $this->PARSEVARS [$matches [1] [$i]], $string );
                                    }
                            }
                            RETURN $string;
                }
                FUNCTION value_defined($value, $field = '', $params = '') {
                    $var = $this->PARSEVARS [$value];
                    if ($field {0} == '.') {
                         $field = substr ( $field, 1 );
                    }
                    # echo "$value, $field, $params <BR>";
                    if (is_object ( $var )) {
                         if (method_exists ( $var, $field )) {
                             eval ( '$return = $var->' . $field . '(' . $this->parseParamString ( $params ) . ');' );
                             RETURN ((! empty ( $return )) || ($return === TRUE));
                         } ELSEif ((strcasecmp ( $field, 'id' ) != 0) && method_exists ( $var, 'get' )) {
                             $result = $var->get ( $field );
                             RETURN (! empty ( $result ) || $result === TRUE);
                         } ELSEif ((strcasecmp ( $field, 'id' ) == 0) && method_exists ( $var, 'getId' )) {
                             $result = $var->getId ();
                             RETURN (! empty ( $result ) || $result === TRUE);
                         }
                    } else {
                     RETURN (! empty ( $var ) || $var === TRUE);
                    }
                }
                FUNCTION parse_defined($template) {
                    $lines = split ( "'n", $template );
                    $newTemplate = "";
                    $ifdefs = FALSE;
                    $depth = 0;
                    $needparsedef [$depth] ["defs"] = FALSE;
                    $needparsedef [$depth] ["parse"] = TRUE;
                    WHILE ( list ( $num, $line ) = each ( $lines ) ) {
                         if (((! $needparsedef [$depth] ["defs"]) || ($needparsedef [$depth] ["parse"])) && (strpos ( $line, "IFDEF:" ) === FALSE) && (strpos ( $line, "IFNDEF:" ) === FALSE) && (strpos ( $line, "ELSE" ) === FALSE) && (strpos ( $line, "ENDIF" ) === FALSE)) {
                         $newTemplate .= trim ( $line ) . "'n";
                         }
                         if (preg_match ( "/<!--'s*IFDEF:'s*([a-zA-Z_][a-zA-Z0-9_]+)('.|'-'>)?([a-zA-Z_][a-zA-Z0-9_]+)?'(?('s*',?'".*'"'s*',?|'s*',?[a-z0-9'_]*'s*',?)')?'s*-->/i", $line, $regs )) {
                                 $depth ++;
                                 $needparsedef [$depth] ["defs"] = TRUE;
                                 if ($this->value_defined ( $regs [1], $regs [3], $regs [4] )){
                                     $needparsedef [$depth] ["parse"] = $needparsedef [$depth - 1] ["parse"]; 
                                 }else{
                                     $needparsedef [$depth] ["parse"] = FALSE;
                                 }
                         }
                         if (preg_match ( "/<!--'s*IFNDEF:'s*([a-zA-Z_][a-zA-Z0-9_]+)('.|'-'>)?([a-zA-Z_][a-zA-Z0-9_]+)?'(?('s*',?'".*'"'s*',?|'s*',?[a-z0-9'_]*'s*',?)')?'s*-->/i", $line, $regs )) {
                             $depth ++;
                             $needparsedef [$depth] ["defs"] = TRUE;
                         }
                         if (! $this->value_defined ( $regs [1], $regs [3], $regs [4] )){
                             $needparsedef [$depth] ["parse"] = $needparsedef [$depth - 1] ["parse"]; 
                         }else{
                             $needparsedef [$depth] ["parse"] = FALSE;}
                         }
                        // ELSE block
                        if (preg_match ( "/<!--'s*ELSE's*-->/i", $line )) {
                             if ($needparsedef [$depth] ["defs"]){
                                 $needparsedef [$depth] ["parse"] = (! ($needparsedef [$depth] ["parse"]) & $needparsedef [$depth - 1] ["parse"]);
                             }
                             if (preg_match ( "/<!--'s*ENDIF's*-->/i", $line )) {
                                 $needparsedef [$depth] ["defs"] = FALSE;
                                 $depth --;
                             }
                        }
                    if ($depth){
                     $this->error ( 'Some nonclosed IDEFS blocks', 0 );
                    }
                    RETURN $newTemplate;
                }
                FUNCTION parse_template($template, $ft_array) {
                    $matches=array();
                    if (preg_match_all ( '/'{([a-zA-Z_][a-zA-Z0-9_]+)('.|'-'>)([a-zA-Z_][a-zA-Z0-9_]+)'(?('s*',?'".*?'"'s*',?|'s*',?[a-z0-9'_]*'s*',?)')?'}/i', $template, $matches )) {
                         FOR($i = 0; $i < count ( $matches [0] ); ++ $i) {
                             $obj = $ft_array [$matches [1] [$i]];
                             if ((is_object ( $obj ) && method_exists ( $obj, $matches [3] [$i] ))) {
                                 eval ( '$return = $obj->' . $matches [3] [$i] . '(' . $this->parseParamString ( $matches [4] [$i] ) . ');' );
                                 $template = str_replace ( $matches [0] [$i], $return, $template );
                             } else if (is_object ( $obj ) && ($matches [3] [$i] == 'id') && method_exists ( $obj, 'getId' )){
                                 $template = str_replace ( $matches [0] [$i], $obj->getId (), $template ); 
                             }else if (is_object ( $obj ) && method_exists ( $obj, 'get' )){
                             $template = str_replace ( $matches [0] [$i], $obj->get ( $matches [3] [$i] ), $template ); }else if (! is_object ( $obj )){
                                 $template = str_replace ( $matches [0] [$i], '', $template );
                             }
                         } //end for loop
                    } //end if 

                    if (preg_match_all ( '/<'!'-'-'s*#include's+file="(['{'}a-zA-Z0-9_'.'-'/]+)"'s*''-'->/i', $template, $matches )) {
                         FOR($i = 0; $i < count ( $matches [0] ); $i ++) {
                             $file_path = $matches [1] [$i];
                             FOREACH ( $ft_array as $key => $value ) {
                                 if (! empty ( $key )) {
                                     $key = '{' . "$key" . '}';
                                     $file_path = str_replace ( "$key", "$value", "$file_path" );
                                 }
                             } //foreach
                             $content = '';
                             if (! isset ( $ft_array [$file_path] )) {
                                 if (! file_exists ( $file_path )){
                                    $file_path = $this->ROOT . $file_path;
                                 }
                                 if (! file_exists ( $file_path )){
                                    $file_path = $this->ROOT . basename ( $file_path );
                                 }
                                 if (file_exists ( $file_path )) {
                                    $content = ((function_exists ( 'file_get_contents' ))) ? file_get_contents ( $file_path ) : implode ( "'n", file ( $file_path ) );
                                 } else {
                                    $content = '';
                                 }
                             } else {
                                 $content = $ft_array [$file_path];
                                 $template = str_replace ( $matches [0] [$i], $content, $template );
                             }
                         } //for
                    } //end preg_match_all
                    reset ( $ft_array );
                    WHILE ( list ( $key, $val ) = each ( $ft_array ) ) {
                         if (! (empty ( $key ))) {
                             if (gettype ( $val ) != "string") {
                                 settype ( $val, "string" );
                             }
                             $key = '{' . "$key" . '}'; 
                             $template = str_replace ( "$key", "$val", "$template" ); 
                         }
                    }

                    $template = ereg_replace ( "{([A-Za-z0-9_'.]+)}", "", $template ); 
                    $template = preg_replace ( "/(<!--'s*IFDEF:'s*([a-zA-Z_][a-zA-Z0-9_]+)('.|'-'>)?([a-zA-Z_][a-zA-Z0-9_]+)?'(?('s*',?'".*?'"'s*',?|'s*',?[a-z0-9'_]*'s*',?)')?'s*-->)/i", "'n$0'n", $template );
                    $template = preg_replace ( "/(<!--'s*IFNDEF:'s*([a-zA-Z_][a-zA-Z0-9_]+)('.|'-'>)?([a-zA-Z_][a-zA-Z0-9_]+)?'(?('s*',?'".*?'"'s*',?|'s*',?[a-z0-9'_]*'s*',?)')?'s*-->)/i", "'n$0'n", $template );
                    $template = preg_replace ( "/(<!--'s*ELSE's*-->)/i", "'n''0'n", $template );
                    $template = preg_replace ( "/(<!--'s*ENDIF's*-->)/i", "'n''0'n", $template );
                     WHILE ( list ( $num, $line ) = each ( $lines ) ) {
                        if (! $inside_block) {
                            $template .= "$line'n";
                        }
                    }
                    $template = $this->parse_defined ( $template );
                    RETURN $template;
                } 
                FUNCTION parse($ReturnVar, $FileTags) {
                    FOREACH ( $this->PATTERN_VARS_DEFINE as $value ){
                         $this->multiple_assign_define ( "$value" );
                    }
                    FOREACH ( $this->PATTERN_VARS_VARIABLE as $value ){
                         $this->multiple_assign ( "$value" );
                    }
                    $append = FALSE;
                    $this->LAST = $ReturnVar;
                    $this->HANDLE [$ReturnVar] = 1;
                    if (gettype ( $FileTags ) == "array") {
                         unset ( $this->$ReturnVar ); 
                         WHILE ( list ( $key, $val ) = each ( $FileTags ) ) {
                             if ((! isset ( $this->$val )) || (empty ( $this->$val ))) {
                                 $this->LOADED ["$val"] = 1;
                                 $fileName = $this->FILELIST ["$val"];
                                 $this->$val = $this->get_template ( $fileName );
                             }
                             $this->$ReturnVar = $this->parse_template ( $this->$val, $this->PARSEVARS );
                             //  For recursive calls.
                             $this->assign ( array ($ReturnVar => $this->$ReturnVar ) );
                         }
                    } else {
                        $val = $FileTags;
                        if ((substr ( $val, 0, 1 )) == '.') {
                            $append = TRUE;
                            $val = substr ( $val, 1 );
                        }
                        if ((! isset ( $this->$val )) || (empty ( $this->$val ))) {
                            $this->LOADED ["$val"] = 1;
                            $fileName = $this->FILELIST ["$val"];
                            $this->$val = $this->get_template ( $fileName );
                        }
                        if ($append) {
                            if (isset ( $this->$ReturnVar )) {
                                $this->$ReturnVar .= $this->parse_template ( $this->$val, $this->PARSEVARS );
                            } else {
                                $this->$ReturnVar = $this->parse_template ( $this->$val, $this->PARSEVARS );
                            }
                        } else {
                            $this->$ReturnVar = $this->parse_template ( $this->$val, $this->PARSEVARS );
                        }
                        $this->assign ( array ($ReturnVar => $this->$ReturnVar ) );
                    }
                    RETURN;
                }
                FUNCTION getfast($template = "") {
                    if (empty ( $template )) {
                        $template = $this->LAST;
                    }
                    // "$this->$template" not initialize here!
                    if ((! (isset ( $this->$template ))) || (empty ( $this->$template ))) {
                         $this->error ( "Nothing parsed, nothing printed", 0 );
                         RETURN;
                    } else {
                         if (! get_magic_quotes_gpc ()){
                             $this->$template = stripslashes ( $this->$template );
                         }
                         RETURN $this->$template;
                    }
                } 
                FUNCTION fetch($template = "") {
                    if (empty ( $template )) {
                         $template = $this->LAST;
                    }
                    if ((! (isset ( $this->$template ))) || (empty ( $this->$template ))) {
                         $this->error ( "Nothing parsed, nothing printed", 0 );
                         RETURN "";
                    }
                    RETURN ($this->$template);
                }
                FUNCTION define($fileList, $value = null) {
                    if ((gettype ( $fileList ) != "array") && ! is_null ( $value )){
                     $fileList = array ($fileList => $value );
                    }
                    WHILE ( list ( $FileTag, $FileName ) = each ( $fileList ) ) {
                         $this->FILELIST ["$FileTag"] = $FileName;
                    }
                    RETURN TRUE;
                }
                FUNCTION clear_href($href) {
                    if (! empty ( $href )) {
                         if ((gettype ( $href )) != "array") {
                                 unset ( $this->PARSEVARS [$href] );
                                 RETURN;
                         } else {
                            FOREACH ( $href as $value ){
                                    unset ( $this->PARSEVARS [$value] );
                                    RETURN;
                            }
                         }
                    } else {
                         // Empty - clear them all
                         $this->clear_assign ();
                    }
                    RETURN;
                }
                FUNCTION clear_assign() {
        if (! (empty ( $this->PARSEVARS ))) {
            WHILE ( list ( $Ref, $Val ) = each ( $this->PARSEVARS ) ) {
                unset ( $this->PARSEVARS ["$Ref"] );
            }
        }
                }
                FUNCTION assign_from_array($Arr, $Keys) {
                    if (gettype ( $Arr ) == "array") {
                         foreach ( $Keys as $k ){
                            if (! empty ( $k )){
                               $this->PARSEVARS [strtoupper ( $k )] = str_replace ( '&amp;#', '&#', $Arr [$k] );
                            }
                         }
                    }
                }
                FUNCTION assign($ft_array, $trailer = "") {
                    if (gettype ( $ft_array ) == "array") {
                         WHILE ( list ( $key, $val ) = each ( $ft_array ) ) {
                             if (! (empty ( $key ))) {
                                 if (! is_object ( $val )){
                                     $this->PARSEVARS ["$key"] = str_replace ( '&amp;#', '&#', $val );
                                 } else{
                                     $this->PARSEVARS ["$key"] = $val; 
                                 }
                            }
                         }
                    } else {
                         if (! empty ( $ft_array )) {
                             if (! is_object ( $trailer )){
                                $this->PARSEVARS ["$ft_array"] = str_replace ( '&amp;#', '&#', $trailer ); 
                             }else{
                                $this->PARSEVARS ["$ft_array"] = $trailer; 
                             }
                         }
                    }
                }
                FUNCTION get_assigned($ft_name = "") {
                    if (empty ( $ft_name )) {
                        RETURN FALSE;
                    }
                    if (isset ( $this->PARSEVARS ["$ft_name"] )) {
                        RETURN ($this->PARSEVARS ["$ft_name"]);
                    } else {
                     RETURN FALSE;
                    }
                }
                FUNCTION error($errorMsg, $die = 0) {
                        $this->ERROR = $errorMsg;
                        echo "ERROR: $this->ERROR <BR> 'n";
                    if ($die == 1) {
                        exit ();
                    }
                    RETURN;
                } 
                FUNCTION multiple_assign($pattern) {
                    WHILE ( list ( $key, $value ) = each ( $GLOBALS ) ) {
                        if (substr ( $key, 0, strlen ( $pattern ) ) == $pattern) {
                           $this->assign ( strtoupper ( $key ), $value );
                        }
                    }
                    reset ( $GLOBALS );
                } 
                FUNCTION multiple_assign_define($pattern) {
                    $ar = get_defined_constants ();
                    FOREACH ( $ar as $key => $def ){
                         if (substr ( $key, 0, strlen ( $pattern ) ) == $pattern){
                             $this->assign ( strtoupper ( $key ), $def );
                         }
                    }
                } 
        } // End Class
    ?>

回答我的第一个问题:

变量"$this->$template"对 parse_and_return() 不可见有两个原因;

原因 1:"$this->$template"变量指向 FastTemplate 类$TPL的实例变量,该变量在调用 parse() 之前不存在。parse() 函数解析 bar.tpl 文件并解析此文件的 FastTemplate {VARS}。在 FastTemplate 对象中创建实例变量$TPL并分配 bar.tpl 文件的内容。$TPL变量在创建之前对任何成员函数都不可见。

原因 2:$template 是局部变量,$this->$template 是局部变量;仅是 fetch() 函数的局部变量。由于这些变量的作用域是局部的,因此如果您尝试在其他成员函数中使用它们,它们将生成并出错。但是,创建$TPL实例变量后,只需使用 $this->TPL 即可从任何成员函数访问其数据值。

回答我的第二个问题:

如上所述,"$this->$template"是一个局部变量变量,指的是使用 bar.tpl 文件内容值初始化的实例变量$TPL。这个$TPL变量在 parse() 函数内的 382-388 行附近或行上初始化。以下表达式用于初始化$TPL:"$this->$ReturnVar = $this->parse_template ($this->$val, $this->PARSEVARS )"。

$ReturnVar变量是 parse() 函数定义中的第一个参数,例如 FUNCTION parse($ReturnVar, $FileTags)。$ReturnVar变量被传递了一个字符串值为"TPL"的参数。现在,您可以使用变量变量访问变量的地址,在本例中为 $$ReturnVar 访问字符串"TPL"的地址。由于"TPL"是 FastTemplate 对象的实例变量,因此必须使用伪变量"$this->"来访问它。因此,变量的结构为 $this->$ReturnVar。这将创建$TPL变量并访问其地址,并为地址分配 bar.tpl 文件的内容。

巧合的是,在此示例中,对象被命名为 $tpl 但可以使用任何名称。

结束语 - 我的目标是通过排除所有变量并使用更直接的编码方法来简化此代码。我认为过度使用变量(指针)会使您的代码变得复杂且难以遵循。