I worked through a tutorial I found which built a small application framework and can’t get the controller that parses the URL into controller, method and parameters to work properly.
I have two methods in the Client controller: index() and display(). But both of my pages are taking me to the view in the index methoid.
I have narrowed things down to a line in the App controller that returns false instead of true, so the correct method is not set.
Could you please take a look at my class and tell me if you see what is causing this issue?
<?php
class App
{
// Set default controller and default method
protected $controller = 'Home';
protected $method = 'index';
protected $params = [];
public function __construct()
{
$url = $this->parseUrl();
// get the controller
if (file_exists('../app/controllers/' . $url[0] . '.php')) {
$this->controller = $url[0];
unset($url[0]);
}
require_once INC_ROOT . '/app/controllers/' . ucfirst($this->controller) . '.php';
$this->controller = new $this->controller;
// get the method
if (isset($url[1])) {
if (is_callable($this->controller, $url[1])) { // is_callable here returns false
$this->method = $url[1];
unset($url[1]);
}
}
// if there is anything left over, they are the parameters
$this->params = $url ? array_values($url) : [];
call_user_func_array([$this->controller, $this->method], $this->params);
}
/*** tutorial made this public, but said it might be better to be protected***/
protected function parseUrl()
{
if (isset($_GET['url'])) {
return $url = explode( '/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
}
}
}
So the second parameter of is_callable() has to be a method of the controller? I think the person making the tutorial intended to just check if $url[1} was legitimate. What function would be the best here to replace is_callable()?
I understand. Earlier, the ‘instructor’ defined $url = $this->parseUrl(); and then used $url as a method, but in fact it is an array. He also used method_exists as a substitute for is_callable, which would create the same problem then. I think it is because the 2nd item in the url refers to the method in the controller that is being called.
Could you please recommend to me the best way to handle this -
// Has a second parameter been passed?
// If so, it might be the requested method
if (isset($url[1])) {
if (method_exists($this->controller, $url[1])) {
$this->method = $url[1];
unset($url[1]);
}
}
The explanation in the tutorial was that method_exists just determines if there is a method, but is_callable takes it one step further and checks to see if the method actually works in the situation. so that makes sense sort of. But my results would indicate that (using method_exists) $url[1] is a function, not a method of the controller.
As of PHP 5.3.0 is_callable() reports constructors as not being callable. This affects PHP 5 style constructors (__construct) as well as PHP 4 style constructors (i.e. methods with the same name as the class). Formerly, both cases have been considered callable.
True, version 5.3 can pretty much be forgotten, but maybe the tutorial is an older one?
I have to step away for a few hours, but I’ll check that out this evening. I don’t think the PHP version is too old though - I think the videos were done in 2014 by Alex Garret and posted to YouTube.
Okay, I am having problems understanding what are the required parameters for is_callable to be the most effective in this situation. I finally came up with
if (is_callable(array($this->controller, $url[1]))) {
$this->method = $url[1];
unset($url[1]);
}
which returns true. But I want to make sure it returns true for the right reason.
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1. Accessing protected and private methods from within a class is allowed.