0

I'm trying to put all my PHP functions in a separate file. I'm using require to include them in the controller file but I get errors with undefined variables in the view file. For example:

A function stored in a file 'functions.php' validating my contact form (for the sake of clarity reduced here to validating only one field):

function validateContactForm()
{
    if (empty($_POST['name'])) {
        $name_error = 'Name is required.';
    } else {
        $name = ($_POST['name'];
        if (!preg_match("/^[A-Za-z .'-]+$/", $name)) {
            $name_error = 'Enter a valid name.';
        }
    }               
} 

In my controller I put this require 'functions.php';.

My view file which gives undefined variable errors. It's just an HTML file with PHP code echoing validation messages.

<form 
name="contact" 
action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" 
method="post">

<label 
for="name" 
id="name-form">
Name:
</label>
    <span id="name-error">
    <?php echo $name_error; ?></span>
</form>

It all works great when I put the PHP code without enclosing it in a function on top of the view file. I've tried to return $name in the function, I've tried require_once and also I used $name as an argument in the function: validateContactForm($name) .

I have followed some simple tutorials where return statement is supposed to be enough but obviously I'm missing something.

Looks like my view file can't access the variables in the function validateContactForm().

2
  • 1
    Can you show your effort with return? It's not enough to make the function return a value - you need to store that value in a variable in order to use it, e.g. $var = functionThatReturnsSomething(); or perhaps directly output it like echo functionThatReturnsSomething();. Depends on whether you're going to use it in multiple places or in a single place. Commented Dec 24, 2020 at 10:48
  • 2
    Use classes and not functions; use class attributes and not variables; use spl autoloaders and not require statements. Commented Dec 24, 2020 at 10:51

3 Answers 3

2

Problem:

The variables in your functions.php file have file-scope. You may access them with the use of global or $GLOBALS or the use keyword on anonymous functions.

I recommend, that you use classes to store your functions.
Please note, that it is not good practice to use globals in the first place.

Possible solutions:

Anyway, you could use any one of these options below*:
*This list of options may not be complete.


./lib.php

<?php

// variables have file-scope, can`t be used directly via require
$foo = 1;
$bar = 2;

// anonymous functions can use the keyword `use` to access the variable
$callFoo = function() use ($foo) {
    echo $foo;
};

// with normal functions, we use the global keyword to get the variable 
function callBar() {
    global $bar;
    echo $bar;
}

// alternative to the one above ...
function callBarAlternative() {
    echo $GLOBALS['bar'];
}

// working with classes:
class Foo {
    public $publicFoo = 3;
    private $privateFoo = 4;

    function fooMethod() {
        echo $this->privateFoo;
    }
}

./view.php

<?php

require "lib.php";

?>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="text/html" charset="utf-8">
</head>
<body>
    <?php
        $callFoo();
        callBar();
        callBarAlternative();
        $foo = new Foo();
        echo $foo->publicFoo;
        $foo->fooMethod();
        echo $GLOBALS['bar'];
        global $bar;
        echo $bar;
    ?>
</body>
</html>

The output for these calls will be: 1223422

Sign up to request clarification or add additional context in comments.

Comments

1

The PHP variables inside a function have a local scope and so they are not visible outside. Use the "global" keyword to indicate that the variable is global.

function validateContactForm()
{
    global $name_error, $name;
    if (empty($_POST['name'])) {
        $name_error = 'Name is required.';
    } else {
        $name = ($_POST['name'];
        if (!preg_match("/^[A-Za-z .'-]+$/", $name)) {
            $name_error = 'Enter a valid name.';
        }
    }               
}

1 Comment

Please note that using globals should be considered as a last resort. If a value really isn't needed all across your application at all times, it has no business of being global. Globals can be changed anywhere in the code, which makes debugging that much harder.
0

The most right way for me to do this looks like this (based on the general code logic):

/**
 * @param Array $POST
 */
function validateContactForm($POST){
    
    if( empty($POST['name']) ){
         throw new Exception('Name is required');
    }

    if (!preg_match("/^[A-Za-z .'-]+$/", $POST['name'])) {
        throw new Exception('Enter a valid name');
    }

}

Then in the view you can do:

try {
     validateContactForm($_POST);
}
catch (Exception $e) {
    // show the error to the user somehow..
}

By this way, you can expand the logic in the function however you wish later and not be able to change code elsewhere. You can also check & validate multiple $_POST data.

2 Comments

Please avoid using exceptions for simple validation. Wrong user input is not exceptional and there is no need to introduce a complex construct such as an exception (with a full stack trace and everything) just to convey a message to the user.
@El_Vanja I am quite disagree with that, but ok different opinions are useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.