export variable to previous scope in 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('?&开发者_如何学Pythongt;'.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.
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?
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);
}
?>
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>
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.
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;
}
精彩评论