duanqing3026
2010-08-22 00:46 阅读 37
已采纳

将变量导出到PHP中的上一个范围

Now, before you jump at how you shouldn't mix scopes: I realize this. However, this is a case where either scope mixing must occur or major code duplication must occur—nothing around it. And I'd prefer scope mixing.

That said, I'd like this code:

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

to be able to work as commented. I know it's not possible in most languages—I was able to do it in Ruby, though; and wonder if you can do it with PHP.

The names of variables aren't known beforehand in the real situation.

Again, it's code duplication or this—absolutely no way around it.

Also, it'd be okay if a had to be something like a('b') or something.


In reality, the code is this:

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")));
}

With a call like E_Render::renderError('NotFound', array( 'requested_url' => '/notfound', 'misspelling' => '/reallynotfound' ));

Then, in templates/NotFound.php, you'd have something like:

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

We'd really rather not have our template authors do anything more than that...although $e['requested_url'] could be done if nothing better was available.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

5条回答 默认 最新

  • 已采纳
    dongxindu8753 dongxindu8753 2010-08-22 00:52

    That's why we have 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
    

    Alternatively:

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

    See: compact(), extract()

    Otherwise I don't see a way of doing this without drastically changing the language.

    PS: If you feel this feature is so important, why don't you just use Ruby?

    点赞 评论 复制链接分享
  • douzheren3349 douzheren3349 2010-08-22 00:49

    why can't you return $a from 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
    

    this does not break scope.

    点赞 评论 复制链接分享
  • doudaotui4297 doudaotui4297 2010-08-22 01:09

    I do not understand why you cannot return them as an array. Besides the suggestion @NullUserException gave you, I would suggest the following approach (if you do not take the OOP route).

    function a() {
      $a = "a";
      $b = "b";
      $c = "c";
    
      return array($a, $b, $c);
    }
    
    function b() {
      list($a, $b, $c) = a();
      echo $a . $b . $c;
    }
    
    点赞 评论 复制链接分享
  • dongluo8439 dongluo8439 2010-08-22 01:12

    There's no way to do what you're asking given the restrictions you are imposing. There's never going to be a good reason to do exactly what you are trying to do. There's plenty of better solutions.

    Anyway, the closest you'll get is passing by reference:

    <?php
    function a(&$a, &$b, &$c)
    {
      $a = 1;
      $b = 2;
      $c = 3;
    }
    
    function b()
    {
      a($a, $b, $c);
    }
    ?>
    
    点赞 评论 复制链接分享
  • dsxz84851 dsxz84851 2010-08-22 01:26

    I just ran this code

    -- 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>
    

    And it outputs :

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

    The reason being that since eval() keeps the current scope, any variable declared locally inside the function will also be available locally inside the eval'ed string. Same thing with $this.

    ** UPDATE **

    Since eval() is evil and should be avoided (as kindly suggested), here's a rewrite using simple templating. This way, your designer only has to know the variable name available (in the specs) :

    -- 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>
    
    点赞 评论 复制链接分享

相关推荐