【问题标题】:export variable to previous scope in PHP将变量导出到 PHP 中的先前范围
【发布时间】:2010-08-22 00:46:10
【问题描述】:

现在,在您开始讨论不应该如何混合范围之前:我意识到这一点。但是,在这种情况下,要么必须发生范围混合,要么必须发生主要的代码重复——周围没有任何东西。而且我更喜欢范围混合。

也就是说,我想要这个代码:

function a() {
    $a = "a";
    $b = "b";
    $c = "c";
}
function b() {
    a();
    echo $a . $b . $c;
}
b(); // Output: abc
echo $a; // Should raise a notice that $a is undefined

能够按照评论工作。我知道这在大多数语言中是不可能的——不过我可以在 Ruby 中做到这一点;并想知道你是否可以用 PHP 做到这一点。

在实际情况下,变量的名称是事先不知道的。

同样,这是代码重复或这个——绝对没有办法解决。

另外,如果 a 必须是 a('b') 之类的东西,那也没关系。


实际上,代码是这样的:

static function renderError($what, $vararray) {
    foreach($vararray as $key => $val) { /* this foreach is the code we want to decouple */
        $key = 'e_'.$key;
        $$key = htmlspecialchars($val);
    }
    ob_clean();
    exit(eval('?>'.file_get_contents(ROOT."/templates/$what.php")));
}

E_Render::renderError('NotFound', array( 'requested_url' => '/notfound', 'misspelling' => '/reallynotfound' ));这样的电话

然后,在 templates/NotFound.php 中,您将有类似的内容:

<html>
<body>
<?php echo $e_requested_url; ?> could not be found. Did you mean <?php echo $e_misspelling: ?>?
</body>
</html>

我们真的不想让我们的模板作者做更多的事情......尽管如果没有更好的可用,$e['requested_url'] 可以做。

【问题讨论】:

    标签: php scope


    【解决方案1】:

    这就是我们有 OO 的原因:

    class Foo {
    
        function a() {
            $this->a = "a";
            $this->b = "b";
            $this->c = "c";
        }
    
        function b() {
            $this->a();
            echo $this->a . $this->b . $this->c;
        }
    }
    
    $f = new Foo;
    $f->b(); // Output: abc
    echo $a; // Should raise a notice that $a is undefined
    

    或者:

    function a() {
        $a = "a";
        $b = "b";
        $c = "c";
    
        return compact('a', 'b', 'c');
    }
    
    function b() {
        extract(a());
        echo $a . $b . $c;
    }
    

    请参阅:compact()extract()

    否则我看不到在不彻底改变语言的情况下这样做的方法。

    PS:如果你觉得这个特性如此重要,为什么不直接使用 Ruby?

    【讨论】:

    • 保留变量名 $a、$b、$c 至关重要。哦,好吧。
    • +1 你先得到它。您没有将 $a,$band $c 声明为类成员?
    • @NAVEED 不必。 PHP 可以在运行时添加类成员
    • @aha 查看我的替代答案
    • extract() 正是我想要的。谢谢!
    【解决方案2】:

    鉴于您施加的限制,您无法按照您的要求进行操作。永远不会有充分的理由去做你想做的事。有很多更好的解决方案。

    无论如何,最接近的是通过引用传递:

    <?php
    function a(&$a, &$b, &$c)
    {
      $a = 1;
      $b = 2;
      $c = 3;
    }
    
    function b()
    {
      a($a, $b, $c);
    }
    ?>
    

    【讨论】:

      【解决方案3】:

      我刚刚运行了这段代码

      -- var1.php

      <?php
      
      function a($vars) {
         foreach ($vars as $var => $val) {
            $$var = $val;
         }
      
         echo eval('?>' . file_get_contents('var2.php') . '<?php ');
      };
      
      
      a(array('a' => 'foo', 'b' => 'bar', 'c' => 'baz'));
      

      -- var2.php

      <html>
         <body>
            <div><?= '$a = "' . $a . '"' ?></div>
            <div><?= '$b = "' . $b . '"' ?></div>
            <div><?= '$c = "' . $c . '"' ?></div>
         </body>
      </html>
      

      它输出:

      $a = "foo"
      $b = "bar"
      $c = "baz"
      

      原因是因为eval() 保持当前范围,所以在函数内本地声明的任何变量也将在 eval'ed 字符串中本地可用。 $this 也是一样。

      ** 更新 **

      由于eval()邪恶 并且应该避免(如善意的建议),这里是使用简单模板的重写。这样,您的设计师只需知道可用的变量名称(在规范中):

      -- var1.php

      <?php
      
      function showError($error, $vars) {
      
         $template = file_get_contents("{$error}.php");
         $keys = array();
         $values = array();
         foreach ($vars as $var => $val) {
            $keys[] = '@{e_'.$var.'}';
            $values[] = $val;
         }
      
         echo str_replace($keys, $values, $template);
      };
      
      showError('template1', array('value' => 300, 'message' => 'Something foo'));
      

      -- template1.php

      <html>
         <body>
            <div>Error <span style="font-weight: bold; color: red;">@{e_value}</span></div>
            <div>The message was : <em>@{e_message}</em></div>
         </body>
      </html>
      

      【讨论】:

      • ... 好吧,关于评估足够公平。至于短标签,这是您的意见。我正在更新答案,所以根本没有 eval() 。开心吗?
      • 短标签是一场噩梦。许多服务器都禁用了它们,让人们一无所知,导致thisthis 之类的问题。而且它们也不符合标准。这是一个愚蠢的“功能”,一开始就不应该添加。
      • 我一直在使用 justhost 和 1and1,并且一直使用 Ubuntu 作为我的开发站,并且都启用了该选项...我理解这种困惑,但我不同意;这个“功能”非常有用(我喜欢 IMO)。到目前为止,我只看到 Windows 服务器禁用了它们。但我可能弄错了。简而言之,我很少看到这个问题,即使遇到,也很容易修复/解决。说得够多了。
      • 此外,我不建议在源代码的开头使用短标签,但仅用于输出 (= ?>)。 (bin-co.com/php/articles/using_php_short_tags.php)
      • 对于这样的事情——它是一个提供的文件,它保证代码与包中的其他任何东西一样安全——eval 是可以的,实际上比模板系统的性能要好得多。当然,eval 不应该与用户提供的数据一起使用——但这几乎就像将它用作包含一样;我希望你不会反对。 :)
      【解决方案4】:

      为什么不能从 a() 返回 $a?

      function a() {
          $a = "a";
          return $a;
      }
      function b() {
          $a = a();
          echo $a;
      }
      b(); // Output: a
      echo $a; // Should raise a notice that $a is undefined
      

      这不会破坏范围。

      【讨论】:

      • 查看已编辑的问题。我需要能够声明多个变量并将它们不在数组中。另外,在实际情况下,我不会事先知道变量的名称。
      • 好的,你能解释一下 a) 为什么它不能是一个数组,因为你可以只返回一个数组,而 $a 与 $array['a'] 和 b) 之间的区别是什么?为您的问题提供更多背景信息,因为我还没有看到必须破坏范围的原因。
      • 如果你事先不知道变量名,你怎么知道在 b() 中使用什么?再次,请为该问题提供更多背景信息
      • 请查看编辑后的回复。虽然我相信 NullUserException 用extract() 给了我正确的方法。
      【解决方案5】:

      我不明白为什么不能将它们作为数组返回。除了@NullUserException 给你的建议,我会建议以下方法(如果你不走OOP路线)。

      function a() {
        $a = "a";
        $b = "b";
        $c = "c";
      
        return array($a, $b, $c);
      }
      
      function b() {
        list($a, $b, $c) = a();
        echo $a . $b . $c;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-19
        • 2011-05-21
        • 2013-07-28
        相关资源
        最近更新 更多