We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Case sensitivity of namespace/class names in \Phalcon\Loader

Given the following snippet:

namespace my_ns;

// create class loader
$loader = new \phalcon\Loader();

// register a namespaces
$loader->registerNamespaces(
   array('my_ns' => __DIR__.'/my_ns/')
);

// register class loader
$loader->register();

$obj = new Object();

everything works as expected (Object.php exists in the specified directory).

But once I say in another file/namespace:

$obj = new \My_ns\Object();

or

namespace my_NS;
$obj = new Object();

the code breaks:

Fatal error: Class '...\Object' not found in ...

Do I miss something to parameterize the class loader to ignore cases and conform with PHP rules (different cases in namespace/class identifiers are to be ignored)? Or how should this be handled?

It would be very easy for the class loader to ignore differently cased namespaces (convert to lower case). As it obviously is not implemented this way, why not? What is the intention?

Thank you.

edit: This question is not about different casing on different file systems. The question is about the registered namespace, not about what is or is not stored in the file system.

I just don't know why you want to have namespace uppercase and folder name lowercase. Make everything just the same.

edited Jun '16

Thank you for your reply. It is not about what I want. Imagine you write a library and give it to another team.

After:

// register a namespaces
$loader->registerNamespaces(
   array('my_ns' => __DIR__.'/my_ns/')
);

shouldn't access to namespace 'my_ns' and to 'MY_NS' both reference to the same registered namespace, as it is in regular PHP? In fact this is a basic feature of PHP. Why break it?

We have for example java devs working with php code as well. They are used to lowercase namespaces. \Phalcon\Di is another good example. Is it \Di or is it \DI. Or maybe \di? It's for this reason that PHP is case insensitiv on those names. Do I need to publish a cheat sheet to my team to explain that PHP ignores case but in our framework we are different? You need to lookup proper case to know what is right. It overcomplicates things when the solution is obvious and in front of your eyes.

That's why my question. What is the intention of this implementation?

And again: The question is not about file systems and how paths are stored there. It's about the registered namespace, that's the left part of the array. I realize that this is not understood.

Then they should learn PSR. Also if namespace of class is \Phalcon\Di then you should use only \Phalcon\Di and that's it. Ide will help you with that. There is PSR-1:

https://www.php-fig.org/psr/psr-1/

Why is it then that Phalcon-Devtools are published with IDE stubs where cases don't stick to that rules? Just to add to the confusement. See also the same issue in Composer:

https://github.com/composer/packagist/issues/186

There people in between write wrappers because maintainers don't want to stick to PHP rules. Btw. I think PHP rules should weigh more heavy than some imaginary PSR's.

What don't stick to that rules ? PSR are php rules.

edited Jun '16

This is how PHP handles namespaces. And to tell you the truth, that's correct way of doing it. You just don't mix and match case of your namespaces. What is the point in that? Another team being lazy to follow the basics? Well, then PHP will help them out with Fatal error and eventually they will learn. :)

One recommended way to use namespaces is outlined in PSR-4, which aims to provide a standard file, class and namespace convention to allow plug-and-play code. In October 2014 the PHP-FIG deprecated the previous autoloading standard: PSR-0, which has been replaced with PSR-4. Currently both are still perfectly usable and PSR-0 is not going away. As PSR-4 requires PHP 5.3 and many PHP 5.2-only projects currently implement PSR-0. Luckily those PHP 5.2-only projects are starting to up their version requirements, meaning PSR-0 is being used less and less.

Everyone should read this: https://www.phptherightway.com/#namespaces

PHP The Right Way

That's not true stamster, php is case insensitive in handling namespaces, for example if you have class Something, you can access it as well using SomeThing etc

Hmmm, I could have sign that I tested such behaviour. I'll check again.

edited Jun '16

I mean it will work once Something is already loaded. If not i think it should ben not loaded but that depends on OS i guess.

There is what I and OP mean : https://sandbox.onlinephpfunctions.com/code/4f455a10b48382f398d5a99e65383781a83fc47e

Internally in php classes and namespaces are case insensitivity.

edited Jun '16

If the framework would have been designed to be completeley foolproof, we would've lost most of the performance gain due to all the various checks and fallbacks.

I don't see how this would be a useful fix/feature, even if PHP is lax and case insensitive. If you let your NS be case insensitive, then *NIX operating systems would throw a fit if you use the wrong letter casing, since they ARE case senstive.

I'd suggest yout to follow community best practices and adhere to PSR standards... And that goes for any dev that uses your code, it will make your life much simpler ;]

edited Jun '16

That's not true stamster, php is case insensitive in handling namespaces, for example if you have class Something, you can access it as well using SomeThing etc

We're talking about namespaces here, not class names!?

I just checked on my project.

namespace STAMSTER;
//change to
namespace STAMSTEr;

Fatal error: Class 'STAMSTEr\Constantia' not found in /usr/share/nginx/site.com/https/proxy/api/controllers/error_handler.php on line 20

Class names are case insensitive, sure. But namespaces are not, like I said.

edited Jun '16

@stamster and @all: I would kindly ask to get familiar with namespace details to not post wrong stuff here that only confuses others. @all: I kindly ask further to stay on-topic and have discussions about file system specifics elsewhere as they are not related to this threads issue and again only confuse others.

Back to the original question: The semantical meaning of "namespace A;" and "namespace a;" is identical. PHP honors this fact by handling namespace names in a case-insensitive way. Phalcon breaks this rule when registering namespaces with Loader::registerNamespaces() and my assumption was there must be a good reason for this. Until now nobody came up with an explanation.

1) File system specifics don't belong here because the issue is about registration of namespaces, not about how to map them to a file system. 2) Speed is not an issue. All that's needed to conform with PHP is a case-insensitive string compare which is cheap and ignorable compared to the load of the actual include/require.

If nobody can give a good explanation for this exception I consider it a design flaw that simply was not thought of before. In that case we should fix it.

edited Jun '16

@stamster: Did you use Phalcon for your test? If so you just confirmed the issue. That's already very useful. Thank you.

<?php
namespace stamster {
   class MyClass {}
}
namespace STAMSTER {
   class MyClass {}
}
?>

run this

edited Jun '16

Why wouldn't file system specifics be relevant here? That's the whole point!

I have Foo\\Bar class in file src/Foo/Bar.php

case_insensitive_register_mechanism("Foo/Bar") Win: OK Nix: OK

case_insensitive_register_mechanism("foo/Bar") Win: OK Nix: NOT FOUND

So if Phalcon were to allow case insensitive namespaces, there would be differences in OS implementations, which is pretty bad news for a framework. Forcing case sensitive namespaces prevents this pitfall

edited Jun '16

Your example is not about namespace registration but about file system mapping. It seems the issue is not understood at all. PHP handles "registered names" case-insensitive. Not so mapping but that's a completely different thing.

I mentioned a few times that the issue is about namespace registration, not about file system mapping:

// useless registration of identical namespaces
$loader->registerNamespaces(
   array('a' => __DIR__.'/folder/to/a/'),
   array('A' => __DIR__.'/folder/to/a/')
);

By the way, the responses here create so much confusion that value for the community is obvious.

Registering namespaces: case-sensitivity does not apply to registered namespaces and should be fixed.

// Register some namespaces
$loader->registerNamespaces(
    array(
       "Example\Base"    => "vendor/example/base/",
       "Example\Adapter" => "vendor/example/adapter/",
       "Example"         => "vendor/example/"
    )
);

Registering prefixes: case-sensitivity does not apply to registered prefixes and should be fixed.

// Register some prefixes
$loader->registerPrefixes(
    array(
        "Example_Base"    => "vendor/example/base/",
        "Example_Adapter" => "vendor/example/adapter/",
        "Example_"        => "vendor/example/"
    )
);

Registering classes: case-sensitivity does not apply to registered classes and should be fixed.

// Register some classes
$loader->registerClasses(
    array(
        "Some"         => "library/OtherComponent/Other/Some.php",
        "Example\Base" => "vendor/example/adapters/Example/BaseClass.php"
    )
);

The strategies where case-sensitivity does apply are registering directories and extensions but that's not the topic here because these functions register file mappings, not names/paces.

$loader->registerDirs();
$loader->setExtensions();

Yes, I used PhalconPHP for that example (real Phalcon project).

And I have never mixed namespace cases.

Now I see that you state only about this portion @Phalcon, but not traversal on the file system.

@stamster: Did you use Phalcon for your test? If so you just confirmed the issue. That's already very useful. Thank you.

<?php
namespace stamster {
  class MyClass {}
}
namespace STAMSTER {
  class MyClass {}
}
?>

run this