返回

PHP函数返回值到全局作用域的4种方法及示例

php

PHP 函数返回值到全局作用域的几种方法

最近处理一个表单提交,需要在 submit_form.php 文件里处理表单数据,并且发一封确认邮件。 我把邮件发送过程封装成了一个 send_mail 函数。问题来了,在同一个文件里,我混用了 PHP 和 HTML,发现函数的 $success 变量没法在 HTML 部分正常显示。 原始代码大概是这样的:

<?php
    $success = "undefined";

    /* ... */

    function send_mail($to, $from, $fromName, $subject, $message) {
        /* headers, etc. */
    
        if (mail($to, $subject, "", $header)) {
            $success = "true";
        } else {
            $success = "false";
        }
    }
?>

<html>
    <body>
        success? <?php echo $success; ?>
    </body
</html>

在 HTML 部分,我想用 <?php echo $success; ?> 来显示邮件发送是否成功,结果却一直是 success? undefined。 这是什么原因呢?又该怎么解决?

问题原因分析

问题出在 PHP 的作用域上。 在函数内部(send_mail)修改的 $success 变量,只是一个局部变量。 它跟函数外面的那个 $success 变量,完全是两个不同的变量,彼此没有任何关系。 函数里的 $success 改变,不会影响外面的 $success。 所以,HTML 部分读取的还是外面的那个初始值为 "undefined" 的 $success

解决方案

有好几种办法可以让函数内部的值“传”到外面。下面咱们一个一个说。

1. 使用 return 返回值

最直接、最常用的方法就是用 return。 函数执行完,把结果通过 return 返回,外面用一个变量接住就行了。

原理: return 语句会立即结束函数的执行,并将指定的值返回给调用者。

代码示例:

<?php
    $success = "undefined";

    function send_mail($to, $from, $fromName, $subject, $message) {
        /* headers, etc. */

        if (mail($to, $subject, "", $header)) {
            return "true"; // 直接返回 "true"
        } else {
            return "false"; // 直接返回 "false"
        }
    }

    // 调用函数,并用 $success 接收返回值
    $success = send_mail($to, $from, $fromName, $subject, $message);
?>

<html>
    <body>
        success? <?php echo $success; ?>
    </body>
</html>

解释:
我们修改 send_mail 函数, 使其通过 return 返回 “true” 或者 “false”, 然后在函数外,调用send_mail函数后用$success 接收返回的结果。

2. 使用 global

如果确实需要在函数内部直接修改全局变量,可以用 global 关键字。

原理: global 关键字声明的变量,会引用全局作用域中的同名变量。 也就是说,在函数内通过 global 声明的变量,和外面的那个是同一个变量。

代码示例:

<?php
    $success = "undefined";

    function send_mail($to, $from, $fromName, $subject, $message) {
        global $success; // 声明 $success 为全局变量

        /* headers, etc. */
    
        if (mail($to, $subject, "", $header)) {
            $success = "true";
        } else {
            $success = "false";
        }
    }

     send_mail($to, $from, $fromName, $subject, $message); //调用函数

?>

<html>
    <body>
        success? <?php echo $success; ?>
    </body>
</html>

解释:
通过在 send_mail 函数里用 global $success; 声明,函数内部对 $success 的修改,就直接反映到全局的 $success 变量上了。

安全建议:
尽量少用 global。 过多使用全局变量会让代码难以维护和调试,也容易出现意料之外的错误。 最好还是用 return 返回值,或者用下面的方法。

3. 使用引用传递 (&)

PHP 的函数参数默认是按值传递的。 如果想在函数内部修改参数的值,并且影响到函数外部,可以用引用传递。

原理: 在参数名前面加上 & 符号,函数接收的就是变量的引用,而不是变量的值的副本。 函数内部对参数的修改,会直接影响到原始变量。

代码示例:

<?php
    $success = "undefined";

    function send_mail($to, $from, $fromName, $subject, $message, &$success) { // &$success
        /* headers, etc. */

        if (mail($to, $subject, "", $header)) {
            $success = "true";
        } else {
            $success = "false";
        }
    }
      send_mail($to, $from, $fromName, $subject, $message, $success); //注意这里
?>

<html>
    <body>
        success? <?php echo $success; ?>
    </body>
</html>

解释:

send_mail 函数增加了一个参数 &$success。 调用函数时,传入 $success 变量。 函数内对 $success 的修改,就直接修改了外面的 $success 变量。

4. (进阶) 使用类和对象

如果你的代码比较复杂,涉及多个函数和变量之间的交互,可以考虑使用面向对象编程(OOP)。 把数据和操作数据的方法封装到一个类里面。

原理: 类定义了对象的属性和方法。 对象是类的实例。 通过对象,可以方便地访问和修改对象内部的数据(属性)。

代码示例:

<?php

class Mailer {
    public $success = "undefined"; // 属性

    public function send_mail($to, $from, $fromName, $subject, $message) {
        /* headers, etc. */

        if (mail($to, $subject, "", $header)) {
            $this->success = "true"; // 修改对象的属性
        } else {
            $this->success = "false"; // 修改对象的属性
        }
    }
}

$mailer = new Mailer(); // 创建对象
$mailer->send_mail($to, $from, $fromName, $subject, $message); // 调用方法

?>

<html>
    <body>
        success? <?php echo $mailer->success; ?>
    </body>
</html>

解释:

  1. 定义了一个 Mailer 类,它有一个 success 属性,初始值为 "undefined"。
  2. send_mail 方法现在是 Mailer 类的一部分。
  3. 方法内部使用 $this->success 来访问和修改对象的 success 属性。
  4. 创建 Mailer 类的一个实例 $mailer
  5. 通过 $mailer 对象调用 send_mail 方法。
  6. 在 HTML 部分,通过 $mailer->success 访问对象的 success 属性。
  7. 这种方法很适合那些比较复杂的,内部各种函数和变量关联较多的。

进阶技巧 : 如果要发送多种类型的邮件,还可以在这个基础上继续扩展。 比如,创建不同的邮件类(比如 ConfirmationMailerNewsletterMailer),它们都继承自一个基础的 Mailer 类,然后根据需要重写 send_mail 方法,或者添加其他特定的方法和属性。这样能进一步让邮件管理变得更结构化。

选择哪种方法?

  • 简单情况,用 return 就够了。
  • 想在函数内直接改全局变量,可以用 global,但要小心。
  • 需要修改传入的参数本身时,用引用传递 (&)。
  • 代码复杂,或者未来可能扩展,用类和对象 (OOP) 更清晰。

不同的情况用不同的解决方法, 根据需求来决定即可.