4

I´m using PHP5 to build my own MVC framework. I have a situation where all of my controllers are in the Controller namespace, as:

namespace Controllers
{
    class Home extends \Framework\Core\Controller 
    {
        ...
     }
}

At the application logic I need to choose wich controller to call from the URL passed from the call, as follows:

namespace Framework\Core;

class Application 
{
     protected $controllerName = 'home';
     protected $methodName = 'index';
     protected $controller;

     public function __construct()
     {
          // Parse the received  URL
          $url = parseUrl();

          // Choose the controller, if file exists
          if (file_exists('../app/controllers/' . $url[0] . '.php'))
          {
              $this->controllerName = $url[0];
              unset($url[0]);
          }

          require_once '../app/controllers/' . $this->controllerName . '.php';

          // Call the controller
          $objToCall = '\\Controllers\\' . $this->controllerName;
          $this->controller = new $objToCall(); <<<======= PROBLEM HERE

          ... Proceed choosing the method and calling the objects method....

          }
    }
}

My problem is:

My controller file is called home.php, and my class is called Home (first letter uppercase). So the code above cannot find /Controllers/home class because the class is /Controllers/Home

On the other way, If I remove the namespace from the controller and call:

$this->controller = new $this->controllerName;

It works fine, even the name being home....

My questions:

a) Why the home is translated to Home if I have no namespaces involved ?

b) How can I solve that problem to call a class from a namespace without needing to know its uppercase/lowercase condition ?

Please do not suggest changing the first letter to uppercase as I may have classes like CustomerReceipt, PersonalCashWithdrawl, etc..

Thanks for helping.

3
  • 1
    Namespacing uses \ not /, so $objToCall = '\\Controllers\\' . $this->controllerName; Commented Aug 14, 2015 at 17:48
  • Right... Type error. Corrected in code. But still don´t work... Commented Aug 14, 2015 at 17:52
  • When resolving use Controllers\Home does it search for Home.php or Home class? Commented Aug 14, 2015 at 18:08

2 Answers 2

3

What you could do is create an array that would match files with classes.

  1. Read all files in your /controllers/ folder
  2. Create an associative array where you match the lowercase version of the file with the actual format
  3. Use this associative array to get the correct file and do not have to worry about the case.

For instance, if your folder contains:

  • home.php
  • RecipeForDisaster.php
  • AnotherController.php

The associative array would contain:

Key                   Value
--------------------  ----------------------------
home                  Home.php
recipefordisaster     RecipeForDisaster.php
anothercontroller     AnotherController.php

By building that kind of array, you can match a class (no matter its case) to a file.

Recipe for a disaster

That will achieve what you want but this is, in my opinion, a recipe for disaster. Why ? Because in some OS (Linux, OSX, ...), you can have home.php and Home.php in the same folder. How will you be able to know what file to use ? The provided solution won't work because you, obviously, can't have 2 values for the same key.

Another thing you want to consider is that classes in PHP are case insensitive. That is why namespaces are important. That means that the following code works perfectly:

class myclass {
    public function printme() {
        print 'hello world';
    }
}

$a = new myclass();     // Correct case
$a->printme();

$b = new MyClass();     // "Incorrect" case... but still working
$b->printme();

Suggested solution

I really do think you should match the class name case to the file. That way, you will avoid potential conflicts and make sure you do not wrongly map a class to the wrong file.

I am not advising you to change the first letter to uppercase, I am suggesting that you strictly use the case provided by the class to find the correct path.

The developer should know: if you type the class name incorrectly (meaning without respecting the case), you can't expect the autoloader to work correctly.

Routing

Most frameworks can do auto-routing but also offer the possibility to do manual routing. You could add a routing module that will allow developers to "overwrite" the default routes. By doing that, you will please those who want to respect your standards and those who want to do it their way.

Conclusion

Your questions seem to be simple. But, in fact, there are so many things you will have to consider if you want it to be flexible and avoid being strict.

You could also mix the strategies provided in this answer like this:

  1. Check if the file exists exactly as the user entered it. If it exists, use it. If not, step 2.
  2. Check if the lowercase version of the class name exists. If it exists, use it. If not, step 3.
  3. Browse the folder and try a magical mapping by finding a file that "looks like" the class name (without considering the case).

The question remains: do you want it to be that flexible ? Your call...

Sign up to request clarification or add additional context in comments.

6 Comments

Also, what if he has 100 controllers then he will be creating and iterating this array on every request. May not be a big deal but still bugs me - just saying :D
The answer is theorical. That said, he does not have to iterate the array. It's a direct mapping. Iterating the array when you know the class name would be, IMHO, the wrong way to do things.
Generally I think the best answer would be to play around with other frameworks and learn from them, you know. These were (mostly) built by people who know how stuff works and were proven in time, so you shouldn't just neglect that. :P
I totally agree. I saw this question as "I want to learn" more than "I think it's a good idea to create what has already been created so many times". :-)
Creating your own framework is not a question of "I want to learn more"... There are always business issues not cited here... But this is for another post....
|
2

This is the purpose of routing. Without proper rooting it is going to be quite difficult for you to work around this. The only thing I could think of right now is having controllers composed of a single word only and using ucfirst() on the URL segment. (It is actually the way I've chosen to go in my own framework as it is the fastest and least demanding)

So to answer your questions:

a) This depends on the type of system your server is running on. Under windows case doesn't matter, on linux it does so you have to keep that in mind. As to why it is behaving the way it is - Apparently classes in PHP are case insensitive. (Answered by Maxime)

b) You can solve that problem by using proper routing or having simple controller class names. Or, you could just use the correct case of the letters in the URL when it is not going to be typed in by users. There is also the option to have the file name in lowercase but then you are creating an inconsistency which - if one day you decide to implement autoloading - could bring you trouble, so kind of a bad idea but still a possibility.

Additionally, I have been down the road of creating my own framework as well and I could give you some other tips if you're interested.

3 Comments

ucfirst() is something I did not want to use... I probably will go for same file name. Why naming to lower will create problems on autoload ?
@Mendez well basically when you autoload classes the class name has upper and lower case characters, of course you can strtolower that so I guess I was incorrect. But still not a good idea, IMO - it is good practice to have the class name be the exact same file name - also some IDE's may not work with lowercase file names.
@Mendez I would highly encourage you to consider creating a routing system - there are also some already built like this one from gatakka which doesn't use regular expressions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.