I have a string, route, and i explode it and then i have a classname. $callback = explode('#', $callback); $callback[0] is the classname. I am making a router and based on the class and methed i return this.
I want to get the full namespace and when i use this then it works but now i want to make it dynamically.
How do i concat BaseController to the ::class?
BasController::class
$fullclass = HERE I NEED THE FULL NAMESPACE$callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
Exaple index.php
Router::route('/user/{id}/' , 'BaseController#show');
Router::execute($_SERVER['REQUEST_URI']);
Router:
namespace App;
class Router
{
private static $routes = array();
private function __construct()
{
}
private function __clone()
{
}
public static function route($pattern, $callback)
{
$pattern = $pattern;
self::$routes[$pattern] = $callback;
}
public static function execute($url)
{
foreach (self::$routes as $pattern => $callback) {
if ($pattern == $url) {
$callback = explode('#', $callback);
$fullclass = __NAMESPACE__ . '\\Controllers\\' . $callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
}else{
echo 404;
}
}
}
}
BasController::class returns a full class name in string in that case you can simply concat any string on it. If $callback[0] is a string you can do below code.
$fullclass = BasController::class . $callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
I hope you are trying to retrieve namespace
echo (new \ReflectionClass($object))->getNamespaceName() ;
If you are in that scope try
__NAMESAPCE__
See this document if you are looking for autoload
What i was looking for is giving the class as param into the route
Router::route('/user/{id}/' , App\Controllers\BaseController::class , 'show');
Related
I am just starting with php and I can't create this object.
I call my object with the variable $theClass is a concatenation of a namespace and a variable from a an array.
One var_dump of $theclass show me the right path... the problem start wen I try to create a new $theClass on variable($control) the var_dump show me nothing...
<?php
namespace App\Router;
class Router {
private $routes = [];
private $url;
public function __construct($url){
$this->url = $url;
}
public function get($path, $action){
$this->routes['GET'][$path] = $action;
}
public function match(){
foreach ($this->routes as $key => $routes) {
foreach ($routes as $path => $action) {
if ($this->url === $path) {
$elements = explode('#', $action);
//$this->callController($elements);
$theClass = "App\Controller\\$elements[0]";
// I try this way to 'App\Controller\\' . $elements[0];
var_dump($theClass);
$method = $elements[1];
var_dump($method);
$control = new $theClass();
$control->$method();
}
}
header('HTTP/1.0 404 Not Found');
}
}
}
I'm having a few problems calling a function from a string, as its a lot more complicated than just calling a function, I need to do it inside another class, with another namespace.
I dispatch my routes using this method, I am using TreeRoute package on GitHub.
public function dispatch() {
$uri = substr($_SERVER['REQUEST_URI'], strlen(implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -1)) . '/'));
$method = $_SERVER['REQUEST_METHOD'];
$result = $this->router->dispatch($method, $uri);
if (!isset($result['error'])) {
$handler = $result['handler'];
$params = $result['params'];
// TODO: Call the handler here, but how?
}
else {
switch ($result['error']['code']) {
case 404 :
echo 'Not found handler here';
break;
case 405 :
echo 'Method not allowed handler here';
$allowedMethods = $result['allowed'];
if ($method == 'OPTIONS') {
// OPTIONS method handler here
}
break;
}
}
}
I register routes like this:
public function __construct() {
$this->router = new \TreeRoute\Router();
}
public function setRoutes() {
$this->router->addRoute('GET', '/test', 'App/Controllers/SomeController/test');
}
What I want to do is call function 'test' in class 'SomeController', now 'SomeController has a namespace of 'App\Controllers'.
I looked into calluserfunc but I couldn't work out how to do it with my string format and with a namespace, can someone help me out?
http://php.net/manual/en/function.call-user-func.php
You can call call_user_func with full class path like this:
call_user_func('App\Controllers\SomeController::test', $arg1, $arg2)
// or
call_user_func(['App\Controllers\SomeController', 'test'], $arg1, $arg2)
// or better
use App\Controllers\SomeController;
call_user_func([SomeController::class, 'test'], $arg1, $args2);
I believe this will do the job
if (!isset($result['error'])) {
$handler = $result['handler'];
$params = $result['params'];
$method = substr( strrchr($handler, '/'), 1 ); // get the method's name from $handler string
$class = substr($handler, 0, -strlen($method)-1); // get the class name from $handler string
$class = str_replace('/', '\\', $class); // change slashes for anti-slashes
// then choose one of those :
// if your methods are static :
call_user_func_array([$class, $method], $params);
// otherwise :
(new $class)->{$method}(...$params); // needs php 7
}
I've got some problem.
I want to call static method of class from another class.
Class name and method are created dynamically.
It's not really hard to do like:
$class = 'className';
$method = 'method';
$data = $class::$method();
BUT, i want to to do it like this
class abc {
static public function action() {
//some code
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = $this->class::$this->method();
}
}
And it doesn't work if i don't assign $this->class to a $class variable, and $this->method to a $method variable.
What's the problem?
In PHP 7.0 you can use the code like this:
<?php
class abc {
static public function action() {
return "Hey";
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = $this->class::{$this->method}();
echo $data;
}
}
$xyz = new xyz();
$xyz->test();
For PHP 5.6 and lower you can use the call_user_func function:
<?php
class abc {
static public function action() {
return "Hey";
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = call_user_func([
$this->class,
$this->method
]);
echo $data;
}
}
$xyz = new xyz();
$xyz->test();
The object syntax $this->class, $this->method makes it ambiguous to the parser when combined with :: in a static call. I've tried every combination of variable functions/string interpolation such as {$this->class}::{$this->method}(), etc... with no success. So assigning to a local variable is the only way, or call like this:
$data = call_user_func(array($this->class, $this->method));
$data = call_user_func([$this->class, $this->method]);
$data = call_user_func("{$this->class}::{$this->method}");
If you need to pass arguments use call_user_func_array().
There are few routers out there but I decided to create a very simple route for a very light site.
Here is my index.php
$route = new Route();
$route->add('/', 'Home');
$route->add('/about', 'About');
$route->add('/contact', 'Contact');
Here is my router:
<?php namespace Laws\Route;
use Laws\Controller\Home;
class Route
{
private $_uri = array();
private $_method = array();
private $_route;
public function __construct()
{
}
public function add($uri, $method = null)
{
$this->_uri[] = '/' . trim($uri, '/');
if ($method != null) {
$this->_method[] = $method;
}
}
public function submit()
{
$uriGetParam = isset($_GET['uri']) ? '/' . $_GET['uri'] : '/';
foreach ($this->_uri as $key => $value) {
if (preg_match("#^$value$#", $uriGetParam)) {
$useMethod = $this->_method[$key];
new $useMethod(); // this returns an error (cannot find Home'
new Home(); // this actually works.
}
}
}
}
new $useMethod(); does not work. returns error 'cannot find Home'
new Home(); actually works.
What am I missing here?
You can use your concurrent way for calling a class or you can use this:
call_user_func(array($classname,$methodname))
I am creating my own MVC framework and the way I handle creation of models is as follows:
class ModelFactory {
public function __construct() {
parent::__construct();
}
public static function Create($model, $params = array()) {
if ( ! empty($model)) {
$model = ucfirst(strtolower($model));
$path = 'application/models/' . $model . '.php';
if (file_exists($path)) {
$path = rtrim(str_replace("/", "\\", $path), '.php');
$modelConstruct = new \ReflectionMethod($path, '__construct');
$numParams = $modelConstruct->getNumberOfParameters();
//fill up missing holes with null values
if (count($params) != $numParams) {
$tempArray = array_fill(0, $numParams, null);
$params = ($params + $tempArray);
}
//instead of thi
return new $path($params);
//I want to DO THIS
return new $path($param1, $param2, $param3 ... $paramN)
//where $paramN is the last value from $params array
}
}
return null;
}
}
a simple Model example:
class UsersModel {
public function __construct($userID, $userName) {
//values of these parameters should be passed from Create function
var_dump($userID, $userName);
}
}
Solved:
Thanks to schokocappucino & pozs I fixed it by doing this:
$modelConstruct = new \ReflectionMethod($path, '__construct');
$numParams = $modelConstruct->getNumberOfParameters();
if (count($params) != $numParams) {
$tempArray = array_fill(0, $numParams, '');
$params = ($params + $tempArray);
}
return (new \ReflectionClass($path))->newInstanceArgs($params);
To get the constructor of a class using reflection, use ReflectionClass::getConstructor().
To create a new instance (with the constructor) using an argument list, use ReflectionClass::newInstanceArgs()
return (new ReflectionClass($path))->newInstanceArgs($params);