0

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]);
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
sandrino
  • 65
  • 1
  • 7

1 Answers1

2

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.

Progman
  • 16,827
  • 6
  • 33
  • 48
  • 1
    It depends on what you are trying to do or why you are trying to access the superglobals not directly. But this is the reason why you can't access the them (indirectly) in functions and class methods. – Progman Jun 11 '22 at 20:28