Почему моя локальная функция PHP не может видеть переменную $test и как я могу получить ее значение?

#php #variables #substitution #heredoc #nowdoc

#php #переменные #замена #heredoc #nowdoc

Вопрос:

Я использую операторы PHP HereDoc и NowDoc для создания веб-страниц на моем веб-сайте, с HereDocs для частей, которым нужны значения переменных PHP, подставленные в веб-страницы, и NowDocs для частей, которые используют символы $ для указания операторов jQuery и переменных объектов jQuery в моем JavaScript. Однако это затрудняет чтение и поддержку моих HTML, CSS и JavaScript / jQuery.

Чтобы обойти это, я подумал, что напишу функцию замены для выполнения замены переменных PHP, которую выполняют операторы HereDoc, но для переменных, значения которых присваивались строковыми выражениями или операторами by NowDoc. Таким образом, переменные PHP, указанные в ${variable-name} в строке, будут заменены их значениями, а операторы jQuery и переменные с префиксом $, значения которых, как ожидается, будут объектами jQuery, не заменяются переменными PHP, что в противном случае обычно вызывает ошибку компилятора PHP, когда нет PHP-переменной.переменная с именем, соответствующим оператору jQuery или имени переменной, или логическая ошибка времени выполнения при совпадении имени.

Вот мой код и тест NowDoc, который:

  • присваивает длинную строку, содержащую переменную ${test} PHP, элементу переменной массива PHP, а затем
  • передает массив в качестве параметра моей функции NowHereDoc для выполнения замены переменных / значений PHP.

Однако, когда я запускаю следующий код для создания своей веб-страницы, переменная $test PHP не отображается внутри функции, и вместо желаемого значения подставляется NULL.

 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>

<?php
//
// PHP
//

function NowHereDoc( amp;$_array_ ) { // By Ref array parameter minimizes data movement when calling this function.
    $_l_ = count( $_array_ );
    $_s_ = $_array_[ $_l_ - 1 ]; // Get the last element's string value.

    // Find each ${...} and substitute the variable's value ...

    $_i1_ = 0;
    while( ( $_i1_ = strpos( $_s_, '${', $_i1_ ) ) !== FALSE ) { // Get index of start of a variable name specified
                                                                 //  by ${...} or FALSE when there aren't any {more},
                                                                 // then stop looping.

        $_i2_  = strpos( $_s_, '}', $_i1_ );                     // Get index of end of the ${...} just found.
        $_l_   = $_i2_ - $_i1_   1;                              // Get length of ${...}.
        $_var_ = substr( $_s_, $_i1_, $_l_ );                    // Get the variable's name as a string.
        $_v_   = str_replace( [ '{', '}' ], '', $_var_ );        // Remove { and } from the variable name.
        $_val_ = "$_v_";                                         // Get the value of the specified variable -- this
                                                                 // doesn't find the variable, instead returns NULL!

        // Substitute the variable's value into the original string, $_s_

        // $_s_ = substr_replace( $_s_, $$_var_, $_i1_, $_l_ );  // Replace the single occurance of the variable
                                                                 // with its value. This could to replace occurances
                                                                 // not with in comments, not yet implemented in
                                                                 // function.

         $_s_   = str_replace( $_var_, $_val_, $_s_ );           // Replace all occurances of the variable with its
                                                                 // value.

    } // End of while( ( $_i1_ = strpos( $_s_, '${', $_i1_ ) ) !== FALSE ) ...

    $_array_[ $_l_ - 1 ] = $_s_;                                 // Set the last element's string value to the
                                                                 // updated string in $_s_.

}

// No Variable substitutions allowed in a NowDoc.
$strMAINs[] = <<<'MAIN'
<!-- ======================================================
======================================================
=
= HTML - ${test} - This should be substituted with hi
=
======================================================
====================================================== -->
<p>to be set by this following script</p>
<script id="scriptId">
  //
  // JavaScript!
  //
  // The following jQuery statement shouldn't be changed.
  //

  var $jQVar = $( 'p' ).html( 'there' );
</script>
MAIN;

//
// PHP
//

$test = 'hi';

NowHereDoc( $strMAINs );
?>

<!-- HTML -->
<b>Test of my PHP NowHereDoc function</b>  

Как я могу получить доступ к переменным PHP по их именам, указанным в виде строковых значений, которые являются глобальными или локальными в функции, вызывающей функцию NowHereDoc из нее, без необходимости передавать их в качестве параметров или указывать их как глобальные переменные в функции? Я помню, что видел библиотечную функцию PHP, которая могла возвращать значение, учитывая его имя в виде строки, но я не помню имя функции.

Спасибо

Комментарии:

1. Звучит довольно ужасно для начала. Есть ли какая-либо конкретная причина, по которой вы не можете просто писать HTML и вставлять теги PHP только там, где это необходимо? php.net/manual/en/language.basic-syntax.phpmode.php

2. Я оставил ответ на этот конкретный запрос, но я согласен с @CBroe, что это, вероятно, не лучший подход

3. (Если причина, по которой вы пытаетесь это сделать, заключается в том, что вам нужны шаблоны, которые должны быть изменены не разработчиками — тогда, возможно, лучше использовать существующее шаблонное решение, чем пытаться создать свое собственное.)

4. Я использую Symfony версии v2.8, которая использует PHP-код для создания содержимого HTML / CSS / JavaScript (и jQuery) в строках или операторах echo, но я использую операторы HereDocs и NowDocs, чтобы веб-страницу было легче читать и поддерживать, а строковые выражения для коротких программно управляемых веб-страницсегменты страницы. Здесь я показал <?php .. ?> тег в моем примере, чтобы было понятнее, что я использую PHP для вставки контента в веб-страницу. То, что здесь содержится в теге PHP, обычно соответствует тому, что есть в моем PHP-скрипте на стороне сервера. Фактическое содержимое HTML хранится в строковых переменных PHP, которые отправляются браузером.

5. Вы пробовали использовать шаблоны, включенные в Symfony? symfony.com/doc/2.8/templating.html

Ответ №1:

Чтобы импортировать глобальные переменные в вашу функцию, вы можете сделать это:

 // global scope
$test = 'my string';

function myFunction() {
    global $test;
}
  

Или, если у вас есть анонимная функция, вы можете извлекать переменные из родительской области следующим образом:

 function myOuterFn() {
    $test = 'my string';
    $myInnerFn = function() use ($test) {
        echo $test;
    };
}
  

В ответ на ваш комментарий, если вы перебирали содержимое, чтобы извлечь любые переменные, на которые ссылаются, в массив имен переменных, вы могли бы перебирать этот массив и импортировать их из глобального, как показано в этом примере: https://3v4l.org/rH8J0

Комментарии:

1. Спасибо всем. Однако, в соответствии с использованием global или use, это сделало бы мой NowHereDoc более специфичным для вызова, я надеялся сохранить его достаточно общим, чтобы выполнить несколько вызовов в моем PHP-скрипте и содержать более крупные веб-страницы, менее разбитые сегменты, указанные в операторах NowDoc, а затем вызвать мою функцию NowHereDocдля разрешения любых переменных tPHP, содержащихся в сегменте. Использование параметров было бы более динамичным, если бы я использовал механизм переменных параметров для поддержки нескольких параметров, но я думал, что увидел способ доступа к родительской переменной среды при каждом вызове функции NowHereDoc.

2. Я добавил дополнительный пример внизу, который может помочь в вашем случае использования

3. Мэтт, это действительно помогает, но как насчет переменных, которые определены в функции, которая включает файл php? Эти переменные будут локальными для функции, верно, и оператор globals, который вы показываете, не увидит их, верно? Мне пришлось бы сделать все эти переменные глобальными, чтобы их могла видеть моя функция NowHereDoc с вашим предложением globals. Поскольку моя функция NowHereDoc является вложенной функцией в операторе require внутри другой функции, есть ли способ наследовать родительские переменные?

4. Ну, ключевое слово global работает в обоих направлениях, поэтому вы можете объявить переменные как глобальные в fn, и они будут помещены в глобальное пространство имен: 3v4l.org/O0soh

5. Таким образом, вы могли бы заставить свой fn определить переменные замены как глобальные, а затем импортировать их в свой NowHereDoc fn. Я просто хочу еще раз повторить то, что разные люди говорили в комментариях к вопросу, вы, вероятно, найдете намного меньше проблем в долгосрочной перспективе, используя установленный механизм создания шаблонов, такой как тот, который входит в состав Symfony

Ответ №2:

Хотя это не шаблонное решение, которое может появиться позже, я нашел функцию get_defined_vars() , это была та часть, которую я помнил, но не мог вспомнить ее название. Он получает список определенных переменных, которые находятся в области видимости во время его вызова. В качестве альтернативы, можно создать список переменных вручную и передать в функцию, поскольку большинство переменных в списке определенных переменных, возвращаемых функциями get_define_vars(), не нужны.

 function NowHereDoc(  amp;$_vars_, amp;$_array_ ) { // a by-ref array of variables and their values from the caller's scope.
                                              //
                                              // a by-ref array specifying the web-content as a string that
                                              // contains one or more PHP variables in the ${...} format who's
                                              // values are to be substituted for the variable name.
                                              //
                                              //  amp; By-Ref prefix minimizes data movement when calling this function.
                                              //

    $_l_ = count( $_array_ );
    $_s_ = $_array_[ $_l_ - 1 ]; // Get the last element's string value.

    // Find each ${...} and substitute the variable's value ...

    $_i1_ = 0;
    while( ( $_i1_ = strpos( $_s_, '${', $_i1_ ) ) !== FALSE ) { // Get index of start of a variable name specified
                                                                 //  by ${...} or FALSE when there aren't any {more},
                                                                 // then stop looping.

        $_i2_  = strpos( $_s_, '}', $_i1_ );                     // Get index of end of the ${...} just found.
        $_l_   = $_i2_ - $_i1_   1;                              // Get length of ${...}.
        $_var_ = substr( $_s_, $_i1_, $_l_ );                    // Get the variable's name as a string.
        $_v_   = str_replace( [ '$', '{', '}' ], '', $_var_ );   // Remove { and } from the variable name.
        $_val_ = $_vars_[ $_v_ ];                                // Get the value of the specified variable.

        // Substitute the variable's value into the original string, $_s_

        // $_s_ = substr_replace( $_s_, $_val_, $_i1_, $_l_ );  // Replace the single occurance of the variable
                                                                 // with its value. This could to replace occurances
                                                                 // not with in comments, not yet implemented in
                                                                 // function.

        $_s_   = str_replace( $_var_, $_val_, $_s_ );            // Replace all occurances of the variable with its
                                                                 // value.

    } // End of while( ( $_i1_ = strpos( $_s_, '${', $_i1_ ) ) !== FALSE ) ...

    $_array_[ $_l_ - 1 ] = $_s_;                                 // Set the last element's string value to the
                                                                 // updated string in $_s_.

}

// No variable substitutions.
$strMAINs[] = <<<'MAIN'
<!-- 
=======================================================================
=======================================================================                     
=
= ${test1} ${test2} // ${test1} ${test2} should be substituted with hi there
=          
=======================================================================          
=======================================================================
-->
MAIN;

$test1 = 'hi';
$test2 = 'there';

$vars = get_defined_vars();
NowHereDoc( $vars, $strMAINs );
  

Еще раз, спасибо за помощь, Мэтт и CBroe.