Why the string to variable conversion doesn't work for the _GET variable from another file?

Issue

I have the following code in test.php:

<?php

$request_method = $_SERVER['REQUEST_METHOD']; // contains 'GET', as it should

echo 'json_encode($_GET) = ' . json_encode($_GET); echo "\n"; // works, prints the GET variables
echo "\n";

echo 'json_encode(${\'_\' . \'GET\'}) = ' . json_encode(${'_' . 'GET'}); echo "\n"; // also works, prints the GET variables
echo "\n";

echo '$request_method = ' . $request_method; echo "\n";
echo 'json_encode(${\'_\' . $request_method}) = ' . json_encode(${'_' . $request_method}); echo "\n"; // fails
echo "\n";

$a = 'GET';
echo '$a = ' . $a; echo "\n";
echo 'json_encode(${\'_\' . $a}) = ' . json_encode(${'_' . $a}); echo "\n"; // fails
echo "\n";

$x = '_GET';
echo '$x = ' . $x; echo "\n";
echo 'json_encode(${$x}) = ' . json_encode(${$x}); echo "\n"; // fails

If I do a GET request with the query string ?action=getUsername, it results in the following output:

json_encode($_GET) = {"action":"getUsername"}

json_encode(${'_' . 'GET'}) = {"action":"getUsername"}

$request_method = GET
json_encode(${'_' . $request_method}) = {"action":"getUsername"}

$a = GET
json_encode(${'_' . $a}) = {"action":"getUsername"}

$x = _GET
json_encode(${$x}) = {"action":"getUsername"}

This is OK.

But, when I’m using the code in a function from a different .php file, then I get the following output:

json_encode($_GET) = {"action":"getUsername"}

json_encode(${'_' . 'GET'}) = {"action":"getUsername"}

$request_method = GET
json_encode(${'_' . $request_method}) = null

$a = GET
json_encode(${'_' . $a}) = null

$x = _GET
json_encode(${$x}) = null

I don’t understand what am I doing wrong.

EDIT:

This is AuthController.php, from where I normally do the request but it fails:

class AuthController extends BaseController
{

    protected function handlePostRequest(): void
    {
        switch ($this->action) {
            case 'login': $this->{'handle_' . $this->action}(); break;
            default: $this->respond_action_not_found();
        }
    }

    protected function handleGetRequest(): void
    {
        switch ($this->action) {
            case 'getUsername': $this->{'handle_' . $this->action}(); break;
            default: $this->respond_action_not_found();
        }
    }

    private function handle_login(): void
    {
        echo 'login';
    }

    private function handle_getUsername(): void {
        echo "getUsername";
    }
}

(new AuthController())->handleRequest();

And this is the BaseController.php:

<?php

use JetBrains\PhpStorm\NoReturn;
require_once '../domain/StatusCode.php';


abstract class BaseController
{
    protected string $request_method;
    protected mixed $request_variables;
    protected string $action;

    public function __construct()
    {
        $request_method = $_SERVER['REQUEST_METHOD']; // contains 'GET', as it should

        echo 'json_encode($_GET) = ' . json_encode($_GET); echo "\n"; // works, prints the GET variables
        echo "\n";

        echo 'json_encode(${\'_\' . \'GET\'}) = ' . json_encode(${'_' . 'GET'}); echo "\n"; // also works, prints the GET variables
        echo "\n";

        echo '$request_method = ' . $request_method; echo "\n";
        echo 'json_encode(${\'_\' . $request_method}) = ' . json_encode(${'_' . $request_method}); echo "\n"; // fails
        echo "\n";

        $a = 'GET';
        echo '$a = ' . $a; echo "\n";
        echo 'json_encode(${\'_\' . $a}) = ' . json_encode(${'_' . $a}); echo "\n"; // fails
        echo "\n";

        $x = '_GET';
        echo '$x = ' . $x; echo "\n";
        echo 'json_encode(${$x}) = ' . json_encode(${$x}); echo "\n"; // fails


        echo ""; echo "\n";

//        echo $this->request_method; // 1
//        echo "\n";
//        echo json_encode($_GET); // 2
//        echo "\n";
//        echo json_encode(${'_' . $this->request_method}); // 3
//        echo "\n";
//        echo json_encode(${'_' . $_SERVER['REQUEST_METHOD']}); // 4
//        echo "\n";
//        echo json_encode(${'_' . 'GET'}); // 5
//        echo "\n";
//        $a = "_" . $this->request_method;
//        echo json_encode($a); // 6
//        echo "\n";
//        error_log($a);
//        error_log($$a);
//        echo json_encode($$a); // 7
//        echo "\n";
//        echo "should work: " . json_encode(${'_GET'});
//        echo "\n";
//        echo "request method: " . $this->request_method;
//        echo "\n";
////        $x = ${'_' . $this->request_method};
//        $x = ${'_' . $_SERVER['REQUEST_METHOD']};
//        echo "should work too : " . json_encode($x);
//        echo "\n";
//        echo "should work too : " . $x;
//        echo "\n";

        $this->request_variables = ${'_' . $this->request_method};
        $this->action = $this->request_variables['action'];
    }

    abstract protected function handlePostRequest(): void;
    abstract protected function handleGetRequest(): void;

    public function handleRequest(): void {
        if (!isset($this->action))
            $this->respond(StatusCode::BAD_REQUEST, "Action is not set");

        switch ($this->request_method) {
            case "POST": {$this->handlePostRequest(); break; }
            case "GET": {$this->handleGetRequest(); break; }
            default:
        }
    }

    #[NoReturn] protected function respond(int $status_code, mixed $content = ""): void {
        http_response_code($status_code);
        echo json_decode($content);
        exit;
    }

    #[NoReturn] protected function respond_success(int $status_code, mixed $content = ""): void {
        $this->respond(StatusCode::OK, $content);
    }

    #[NoReturn] protected function respond_action_not_found(): void {
        $this->respond(StatusCode::BAD_REQUEST, "Action not found");
    }

    #[NoReturn] protected function respond_invalid_parameters(string $additional_message = ""): void {
        $this->respond(StatusCode::BAD_REQUEST, "Invalid parameters. " . $additional_message);
    }
}

EDIT 2: Workaround

From @Kubo2 in Superglobals can't be accessed via variable variables in a function?

$a = "_GET";
echo json_encode($GLOBALS[$a]);

Solution

You can’t access the superglobals via variable variables (as you did with expressions like ${'_' . $a}) as stated in the manual Variable variables:

Warning
Please note that variable variables cannot be used with PHP’s Superglobal arrays within functions or class methods. The variable $this is also a special variable that cannot be referenced dynamically.

Answered By – Progman

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published