Viewed   77 times

So, I don't come from a huge PHP background—and I was wondering if in well formed code, one should use the 'superglobals' directly, e.g. in the middle of some function say $_SESSION['x'] = 'y'; or if, like I'd normally do with variables, it's better to send them as arguments that can be used from there, e.g:

class Doer {
    private $sess;
    public function __construct(&$sess) {
        $this->sess =& $sess;
    }
} 

$doer = new Doer($_SESSION);

and then use the Doer->sess version from within Doer and such. (The advantage of this method is that it makes clear that Doer uses $_SESSION.)

What's the accepted PHP design approach for this problem?

 Answers

5

I do like to wrap $_SESSION, $_POST, $_GET, and $_COOKIE into OOP structures.

I use this method to centralize code that handles sanitation and validation, all of the necessary isset () checks, nonces, setcookie parameters, etc. It also allows client code to be more readable (and gives me the illusion that it's more maintainable).

It may be difficult to enforce use of this kind of structure, especially if there are multiple coders. With $_GET, $_POST, and $_COOKIE (I believe), your initialization code can copy the data, then destroy the superglobal. Maybe a clever destructor could make this possible with $_SESSION (wipe $_SESSION on load, write it back in the destructor), though I haven't tried.

I don't usually use any of these enforcement techniques, though. After getting used to it, seeing $_SESSION in code outside the session class just looks strange, and I mostly work solo.

EDIT
Here's some sample client code, in case it helps somebody. I'm sure looking at any of the major frameworks would give you better ideas...

$post = Post::load ();  
$post->numeric ('member_age');  
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
  // do good stuff
  $firstName = $post->member_first_name;
}
else
{
  // do error stuff
}

Post and its friends all derive from a base class that implements the core validation code, adding their own specific functionality like form tokens, session cookie configuration, whatever.

Internally, the class holds a collection of valid data that's extracted from $_POST as the validation methods are called, then returns them as properties using a magic __get method. Failed fields can't be accessed this way. My validation methods (except required) don't fail on empty fields, and many of them use func_get_args to allow them to operate on multiple fields at once. Some of the methods (like money) automatically translate the data into custom value types.

In the error case, I have a way to transform the data into a format that can be saved in the session and used to pre-populate the form and highlight errors after redirecting to the original form.

One way to improve on this would be to store the validation info in a Form class that's used to render the form and power client-side validation, as well as cleaning the data after submission.

Sunday, October 2, 2022
 
notepad
 
2

When people talk about global variables in other languages it means something different to what it does in PHP. That's because variables aren't really global in PHP. The scope of a typical PHP program is one HTTP request. Session variables actually have a wider scope than PHP "global" variables because they typically encompass many HTTP requests.

Often (always?) you can call member functions in methods like preg_replace_callback() like this:

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

See callbacks for more.

The point is that objects have been bolted onto PHP and in some ways lead to some awkwardness.

Don't concern yourself overly with applying standards or constructs from different languages to PHP. Another common pitfall is trying to turn PHP into a pure OOP language by sticking object models on top of everything.

Like anything else, use "global" variables, procedural code, a particular framework and OOP because it makes sense, solves a problem, reduces the amount of code you need to write or makes it more maintainable and easier to understand, not because you think you should.

Monday, August 8, 2022
5

I would suggest using the associative array to pass named parameters, but keep them in the array without extracting them.

function myFunc(array $args) {
    echo "Hi, " . $args['name'];
    // etc
}

There's a couple of reasons for this. Looking at that function, you can quite clearly see that I'm referring to one of the arguments passed into the function. If you extract them, and don't notice the extract() you (or the next guy) will be there scratching your head wondering where this "$name" variable came from. Even if you do know you're extracting the arguments to local variables, it's still a guessing game to a certain degree.

Secondly, it ensures that other code doesn't overwrite the args. You may have written your function expecting only to have arguments named $foo and $bar, so in your other code, you define $baz = 8;, for example. Later on, you might want to expand your function to take a new parameter called "baz" but forget to change your other variables, so no matter what gets passed in the arguments, $baz will always be set to 8.

There are some benefits to using the array too (these apply equally to the methods of extracting or leaving in the array): you can set up a variable at the top of each function called $defaults:

function myFunc (array $args) {
    $default = array(
        "name" => "John Doe",
        "age" => "30"
    );
    // overwrite all the defaults with the arguments
    $args = array_merge($defaults, $args);
    // you *could* extract($args) here if you want

    echo "Name: " . $args['name'] . ", Age: " . $args['age'];
}

myFunc(array("age" => 25)); // "Name: John Doe, Age: 25"

You could even remove all items from $args which don't have a corresponding $default value. This way you know exactly which variables you have.

Sunday, December 11, 2022
 
kadoo
 
1

Use posix_isatty.

This function accepts both a file descriptor (an integer) and a PHP stream. If it receives a PHP stream, it automatically attempts to cast it in order to obtain a file descriptor and use it instead.

Monday, September 26, 2022
 
4

Well, why don't you just test ? ;-)

Note: It is not as easy as you'd think -- read the full answer ;-)


Calling the hello_testing(); function, without setting the variable:

hello_testing();

I get no output -- which indicates isset returned false.


Calling the function, after setting the variable:

$conditional_random = 'blah';
hello_testing();

I get an output:

foo is inside

Which indicates global works as expected, when the variable is set -- well, one should not have any doubt about that ^^



But note that isset will return false if a variable is set, and null!


See the manual page of isset()

Which means that a better test would be:

function hello_testing() {
    global $conditional_random;
    var_dump($conditional_random);
}

hello_testing();

And this displays:

null

No Notice: the variable exists! Even if null.

As I didn't set the variable outside of the function, it shows that global sets the variable -- but it doesn't put a value into it; which means it's null if not already set outside the function.


While:

function hello_testing() {
    //global $conditional_random;
    var_dump($conditional_random);
}

hello_testing();

Gives:

Notice: Undefined variable: conditional_random

It proves that notices are enabled ;-)

And, if global didn't "set" the variable, the previous example would have given the same notice.


And, finally:

function hello_testing() {
    global $conditional_random;
    var_dump($conditional_random);
}

$conditional_random = 'glop';
hello_testing();

Gives:

string 'glop' (length=4)

(This is to purely to demonstrate my example is not tricked ^^)

Saturday, October 8, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :