在使用输出缓冲的 PHP 函数中使用 extract()
Using extract() in PHP function that uses output buffering
我目前正在上一门编码初学者课程,主要侧重于 PHP,在一个练习中,我们正在更改我们的代码,从通过正常命名空间包含模板改为通过函数包含它,以便我们可以使用输出缓冲。为了让它工作,我们使用了 extract() ,虽然我理解 extract 是如何工作的,但我很难理解为什么我们需要使用它来使 include 工作。在通过函数 运行 之前,我们不需要发送或提取新变量。有人能够解释这背后的原因吗?
函数如下所示:
const TEMPLATE_EXTENSION = '.phtml';
const TEMPLATE_FOLDER = 'templates/';
const TEMPLATE_PREFIX = 'cart_view_';
function display($template, $variables, $extension = TEMPLATE_EXTENSION) {
extract($variables);
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
我们是这样称呼它的:
<?php echo display('user', ['users' => $users, 'cart' => $cart]); ?>
<?php echo display('item', ['new_item' => $new_item]); ?>
<?php echo display('items', ['cart' => $cart]); ?>
下面是我们包含的模板中的内容:
<h2>New Item</h2>
<p><?php printf($new_item['name']);?> is $<?php printf($new_item['price']);?></p>
<h2>User: <?php printf($cart['user']); ?></h2>
<p>ID: <?php printf($users[$cart['user']]['id']); ?></p>
<p>Email: <?php printf($users[$cart['user']]['email']); ?></p>
<h2>Cart</h2>
<?php foreach ($cart['items'] as $item) {
printf("<p>%s is $%d</p>\n", $item['name'], $item['price']);
} ?>
变量在索引中已包含的另一个文件中定义。
以前在使用函数缓冲之前,我们只需要这样:
<?php include 'templates/cart_view_user.phtml'; ?>
<?php include 'templates/cart_view_item.phtml'; ?>
<?php include 'templates/cart_view_items.phtml'; ?>
函数确实有自己的变量范围。因此,当您创建 display()
函数时,它看不到它之外有哪些变量可用。在 Variable Scopes in PHP 上查看更多信息。您正在使用 extract()
以便将数组转换为您从例如函数中调用它的范围内的变量。
你的第一个解决方案可能是这样的(我正在弥补变量):
$users = [];
$cart = [];
// you are including the template in the same scope as the variables are defined, aka it will "see"/have access to those variables
include 'templates/cart_view_user.phtml';
现在您已经重构了代码并将包含逻辑移动到函数中。这个函数有自己的本地作用域。
$users = [];
$cart = [];
function display($template, $variables, $extension = TEMPLATE_EXTENSION) {
// you don't have access to $users and $cart here as those are defined in the global scope
extract($variables); // <-- after this call you will have new variables created in the local function scope based on your $variables array
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
所以现在你有两个选择,如果你知道你想在函数中使用哪些变量,你可以使用 global 关键字,但我不鼓励使用它,它可能会导致奇怪的错误你不明白为什么你的变量会被改变(ps 之后你将继续使用 类 而你不会为全局变量而头疼)。
// you can drop $variables from the function signature
function display($template, $extension = TEMPLATE_EXTENSION) {
global $users, $cart, $new_item;
// no extract needed, but please try not using global, it can lead to weird bugs
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
或者您可以使用 extract
在函数范围内创建变量,这样当您包含文件时,它们就可以访问这些变量。这里要注意的是,extract 将使用数组键作为它创建的变量名。这就是您在此调用后传入 display('user', ['users' => $users, 'cart' => $cart]);
的原因,extract
将在函数调用内创建一个 $users
和一个 $cart
变量。如果您使用不同的数组键调用它,例如:display('user', ['u' => $users, 'c' => $cart]);
包含的文件会抱怨找不到变量 $users
和 $cart
.
我希望这对您有所帮助,如果我哪里不清楚,请随时询问更多。
我目前正在上一门编码初学者课程,主要侧重于 PHP,在一个练习中,我们正在更改我们的代码,从通过正常命名空间包含模板改为通过函数包含它,以便我们可以使用输出缓冲。为了让它工作,我们使用了 extract() ,虽然我理解 extract 是如何工作的,但我很难理解为什么我们需要使用它来使 include 工作。在通过函数 运行 之前,我们不需要发送或提取新变量。有人能够解释这背后的原因吗?
函数如下所示:
const TEMPLATE_EXTENSION = '.phtml';
const TEMPLATE_FOLDER = 'templates/';
const TEMPLATE_PREFIX = 'cart_view_';
function display($template, $variables, $extension = TEMPLATE_EXTENSION) {
extract($variables);
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
我们是这样称呼它的:
<?php echo display('user', ['users' => $users, 'cart' => $cart]); ?>
<?php echo display('item', ['new_item' => $new_item]); ?>
<?php echo display('items', ['cart' => $cart]); ?>
下面是我们包含的模板中的内容:
<h2>New Item</h2>
<p><?php printf($new_item['name']);?> is $<?php printf($new_item['price']);?></p>
<h2>User: <?php printf($cart['user']); ?></h2>
<p>ID: <?php printf($users[$cart['user']]['id']); ?></p>
<p>Email: <?php printf($users[$cart['user']]['email']); ?></p>
<h2>Cart</h2>
<?php foreach ($cart['items'] as $item) {
printf("<p>%s is $%d</p>\n", $item['name'], $item['price']);
} ?>
变量在索引中已包含的另一个文件中定义。 以前在使用函数缓冲之前,我们只需要这样:
<?php include 'templates/cart_view_user.phtml'; ?>
<?php include 'templates/cart_view_item.phtml'; ?>
<?php include 'templates/cart_view_items.phtml'; ?>
函数确实有自己的变量范围。因此,当您创建 display()
函数时,它看不到它之外有哪些变量可用。在 Variable Scopes in PHP 上查看更多信息。您正在使用 extract()
以便将数组转换为您从例如函数中调用它的范围内的变量。
你的第一个解决方案可能是这样的(我正在弥补变量):
$users = [];
$cart = [];
// you are including the template in the same scope as the variables are defined, aka it will "see"/have access to those variables
include 'templates/cart_view_user.phtml';
现在您已经重构了代码并将包含逻辑移动到函数中。这个函数有自己的本地作用域。
$users = [];
$cart = [];
function display($template, $variables, $extension = TEMPLATE_EXTENSION) {
// you don't have access to $users and $cart here as those are defined in the global scope
extract($variables); // <-- after this call you will have new variables created in the local function scope based on your $variables array
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
所以现在你有两个选择,如果你知道你想在函数中使用哪些变量,你可以使用 global 关键字,但我不鼓励使用它,它可能会导致奇怪的错误你不明白为什么你的变量会被改变(ps 之后你将继续使用 类 而你不会为全局变量而头疼)。
// you can drop $variables from the function signature
function display($template, $extension = TEMPLATE_EXTENSION) {
global $users, $cart, $new_item;
// no extract needed, but please try not using global, it can lead to weird bugs
ob_start();
include TEMPLATE_FOLDER . TEMPLATE_PREFIX . $template . $extension;
return ob_get_clean();
}
或者您可以使用 extract
在函数范围内创建变量,这样当您包含文件时,它们就可以访问这些变量。这里要注意的是,extract 将使用数组键作为它创建的变量名。这就是您在此调用后传入 display('user', ['users' => $users, 'cart' => $cart]);
的原因,extract
将在函数调用内创建一个 $users
和一个 $cart
变量。如果您使用不同的数组键调用它,例如:display('user', ['u' => $users, 'c' => $cart]);
包含的文件会抱怨找不到变量 $users
和 $cart
.
我希望这对您有所帮助,如果我哪里不清楚,请随时询问更多。