Mendes
Mendes

Reputation: 18561

PHP Class name with variable name and namespace

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.

Upvotes: 4

Views: 1300

Answers (2)

Maxime
Maxime

Reputation: 8989

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...

Upvotes: 3

php_nub_qq
php_nub_qq

Reputation: 16065

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.

Upvotes: 2

Related Questions