0

I am trying to run different classes dynamically in PHP using some hopefully reusable code, but I am having trouble finding the proper way to do it.

Currently, I am running a POST request with the data flowing as follows:

Route::post('/user/create', 'UserController@createItem');

To UserController:


namespace App\Http\Controllers;

use Illuminate\Cache\Repository;
use App\Models\User;

class UserController extends AbstractController{
    const className = 'User';
}

And AbstractController:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use GuzzleHttp\Exception\RequestException;
use App\Models\User;

class AbstractController extends Controller
{

    public function createItem() {
        $inputJSON = file_get_contents('php://input');
        $this->className::buildItem($inputJSON);
        return;
    }
}

Which should ideally call a static method called buildItem()

When I test this by hard coding User into the AbstractController, it works as expected, but when I try to do it this way, I get an error in PostMan:

ErrorException: Undefined property: App\Http\Controllers\UserController::$className in file .../app/Http/Controllers/AbstractController.php on line 14

I have tried declaring and referencing className a few different ways, but can't seem to get this to work. Any help is appreciated!

ccarlson
  • 13
  • 2
  • Does this answer your question? [Dynamic static method call in PHP?](https://stackoverflow.com/questions/2108795/dynamic-static-method-call-in-php) Note: prefer [this solution](https://stackoverflow.com/a/2108815/965834) (unless you're using a *really old* PHP version, which hopefully you aren't). – Jeto Feb 07 '20 at 16:34
  • Also, this is not how you access a class constant. `self::$className` is what you're looking for in this case. – Jeto Feb 07 '20 at 16:36
  • Try a double dollar `$$this->className::buildItem($inputJSON);` – delboy1978uk Feb 07 '20 at 16:39
  • I am looking at the links you've posted. I thought that ```self``` only applies explicitly to the class its called in(in this case, AbstractController, ignoring UserController)? – ccarlson Feb 07 '20 at 16:39
  • @ccarlson Oh indeed, I thought the bottom class was the extending one, not the other way around. `static::$className` it is then. See [late static binding](https://stackoverflow.com/questions/1912902/what-exactly-are-late-static-bindings-in-php). – Jeto Feb 07 '20 at 16:43
  • @Jeto glad to hear I at least know a little bit. lol I implemented the preferred solution, and the error returning is now ```Class 'User' not found in file``` – ccarlson Feb 07 '20 at 16:47
  • I'm not sure I follow. Where would I be implementing ```__NAMESPACE__```? Sorry, just getting my feet wet in this language, so some stuff is still unclear. – ccarlson Feb 07 '20 at 16:50

1 Answers1

0

Since className is defined in the implementation, you can access it using late static binding through static::className.

You also need to prepend the models classes' namespace.

This becomes:

class AbstractController extends Controller
{
  private const MODELS_NAMESPACE = 'App\\Models';

  public function createItem()
  {
    $inputJSON = file_get_contents('php://input');
    $className = self::MODELS_NAMESPACE . '\\' . static::className;
    $className::buildItem($inputJSON);
  }
}

Demo: https://3v4l.org/Ng6bl

Jeto
  • 14,596
  • 2
  • 32
  • 46