Search code examples
phpvariablesscopedefined

Is it possible to get variables with get_defined_vars() but for the actual running script?


I'm trying to create a function to get all user-defined variables for, selectively, unsetting them before the script actually finishes. In order to get all used variables, you must use the get_defined_vars() function PHP provides you with, but it has a caveat (for me, at least...): it only works in the scope it's actually called.

I would like to, ideally, encapsulate it in a function inside my framework core namespace, which is \Helpers\Core so the function would be \Helpers\Core\getVariables().

Actually, my code looks like this:

foreach (array_diff(array_keys(get_defined_vars()), ["_COOKIE", "_ENV", "_FILES", "_GET", "_POST", "_REQUEST", "_SERVER", "_SESSION", "argc", "argv", "GLOBALS", "HTTP_RAW_POST_DATA", "http_response_header", "ignore", "php_errormsg"], ["page"]) as $variable) {
    unset($$variable);
}

Basically, it tries to automate variable selection by:

  • getting all variable names with array_keys(get_defined_vars())
  • defining a set of reserved or system-wide variables like $_GET, $_POST, $_SERVER and so on
  • providing which of your used variables are preserved (in this example, $page)

The problem is I would like not to place this code every place I want to get rid of some variables at. Ideally, I would like to be able to define this as a function and automate its use, but... is there a way to accomplish this but in the current script you call the function from?


Solution

  • You can use $GLOBALS instead of get_defined_vars() to access global scope and to unset global variables:

    $non_user_vars = ["_COOKIE", "_ENV", "_FILES", "_GET", "_POST", "_REQUEST", 
                      "_SERVER", "_SESSION", "argc", "argv", "GLOBALS",
                      "HTTP_RAW_POST_DATA", "http_response_header",
                      "ignore", "php_errormsg"];
    
    $safe_user_vars = ["page"];
    
    $all_vars = array_keys($GLOBALS);
    
    $user_vars = array_diff($all_vars, $non_user_vars, $safe_user_vars);
    
    foreach($user_vars as $variable) {
        unset($GLOBALS[$variable]);
    }
    

    Quick caveats to this approach:

    1. to make it cleaner, I defined the arrays first. This could result in them getting into your $user_vars array (thought it shouldn't if they are not global) so defend against that to avoid throwing an error or other consequences.

    2. Your array of non-user variables is not exhaustive, as when I tested the above, I still got:

      Array
      (
          [2] => HTTP_ENV_VARS
          [6] => HTTP_POST_VARS
          [8] => HTTP_GET_VARS
          [10] => HTTP_COOKIE_VARS
          [12] => HTTP_SERVER_VARS
          [14] => HTTP_POST_FILES
          [16] => test
          [17] => non_user_vars
      )
      

    If you don't want to guess which is pre-defined or visible at runtime, maybe there could be an initial call to the \Helpers\Core\getVariables() that gets the list of variables and stores them statically so your array_diff just needs to diff the initial list with the list at the end to know what is user-defined.