NotionCommotion Posted June 14, 2017 Share Posted June 14, 2017 By using use ($methods), $methods is available within the closure. Can I instead pass new Methods() to Router and somehow access the methods? require_once '../classes/Methods.php'; $methods=new Methods(); require_once '../classes/Router.php'; //$router = new Router(new Methods()); $router = new Router(); $router->get('/^\/?$/', function(){ echo('home'); }); $router->get('/^\/entity\/?$/', function() use ($methods){ echo('display entity'); echo("<pre>".print_r(get_class_methods($methods),1).'</pre>'); }); $router->post('/^\/entity\/?$/', function(){ echo('save'); }); $router->get('/^\/entity\/(\w+)\/(\d+)\/?$/', function($type, $id) use ($methods){ echo("display type $type with id $id"); echo("<pre>".print_r(get_class_methods($methods),1).'</pre>'); }); $router->execute($_SERVER['REQUEST_URI']); class Router { private $routesGet = array(); private $routesPost = array(); //public function __construct($methods){$this->methods=$methods;} public function get($pattern, $callback) { $this->routesGet[$pattern] = $callback; } public function post($pattern, $callback) { $this->routesPost[$pattern] = $callback; } public function execute($uri) { switch($_SERVER['REQUEST_METHOD']) { case 'GET': foreach ($this->routesGet as $pattern => $callback) { if (preg_match($pattern, $uri, $params) === 1) { array_shift($params); return call_user_func_array($callback, array_values($params)); } } break; case 'POST': foreach ($this->routesPost as $pattern => $callback) { if (preg_match($pattern, $uri, $params) === 1) { array_shift($params); return call_user_func_array($callback, array_values($params)); } } break; defaut: trigger_error('Method "'.$_SERVER['REQUEST_METHOD'].'" is not supported', E_USER_ERROR); } } } Quote Link to comment Share on other sites More sharing options...
requinix Posted June 14, 2017 Share Posted June 14, 2017 Short answer: no, you can't. Long answer: no, you can't, but if it were I still wouldn't do it. The router you have now is fairly minimal (not necessarily a bad thing) and adding a concept of a sort of... I forget what it's called but it's an object you pass around that contains arbitrary data... would over-complicate the class and its behavior. Use-ing the variable makes sense to me and I would do that. That said, what you're doing now doesn't make sense. Based on context I assume $methods just a placeholder for more work? Because if it really is merely a new Methods() then you should just do that inside each callback. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted June 14, 2017 Author Share Posted June 14, 2017 Thanks for the short and even more so long answers! I've used Slim which I like, but for this particular project wanted something even slimmer, and will definitely not complicate efforts just to find some way to do so. $methods is just to allow little code to be included in the callback so it is more readable. You mean create the object within each callback? If so, I agree, and will do the later. $router->post('/^\/entity\/?$/', function() use ($methods) { $rsp=$methods->saveSomething($_POST); //Returns [data, responseCode] http_response_code($rsp[1]); header('Content-Type: application/json'); echo json_encode($rsp[0]); }); $router->post('/^\/entity\/?$/', function() { $mySpecificObject=new MySpecificClass(); $rsp=$mySpecificObject->saveSomething($_POST); //Returns [data, responseCode] http_response_code($rsp[1]); //Will actually use a small method for these three lines... header('Content-Type: application/json'); echo json_encode($rsp[0]); }); Quote Link to comment Share on other sites More sharing options...
kicken Posted June 15, 2017 Share Posted June 15, 2017 Technically you could do what you propose by re-binding the closure within the router, but I'd argue that doing such a thing would ultimately make your code more difficult to write and maintain, you're better off just using $methods like you are now. Bad code, don't do this <?php class Methods { public function doSomething(){ echo 'Did something'; } } class Router { public $methods; public function __construct($methods){ $this->methods = $methods; } public function execute($fn){ return call_user_func($fn->bindTo($this)); } } $router = new Router(new Methods); $router->execute(function(){ echo 'Running the closure'; $this->methods->doSomething(); }); Your last three methods you could move out either into the router or after your $router->execute() call. For example create some sort of Response object that just holds the status code, headers, and body and have your routes return that. <?php class Response { private $status; private $headers; private $body; public function __construct($status, $body, $headers = []){ $this->status = $status; $this->headers = $headers; $this->body = $body; } public function output(){ http_response_code($this->status); foreach ($headers as $header){ header($header); } echo $this->body; } } class JSONResponse extends Response { public function __construct($status, $data, $headers){ $headers[] = 'Content-type: application/json'; $body = json_encode($body); parent::__construct($status, $body, $headers); } } // ------------------------------ // $router->post('/^\/entity\/?$/', function() { $mySpecificObject=new MySpecificClass(); $rsp=$mySpecificObject->saveSomething($_POST); //Returns [data, responseCode] return new JSONResponse($rsp[1], $rsp[0]); }); // ------------------------------ // $response = $router->execute($_SERVER['REQUEST_URI']); $response->output(); 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.