I now utilize spl_autoload_register and there's no turning back. So let me gather here for you what I've learned...
1.) the issue mentioned in these docs about case-sensitivity of filenames (Windows vs Linux/Mac): it only comes into play if you don't provide your own custom function as an argument when calling spl_autoload_register. Your function is to accept a single argument which will be the class name that your code is currently trying to access. I observe that the class name comes in with the same letter-casing as that you are actually using in your code base (mixed-case or not). I am not doing/using namespaces, but as a best practice, and to make your implementation straight-forward and predictable, go with fileName===className (1:1).
2.) I often refactor my code-base's directory structure as my code base morphs. I'm not using namespaces, but even if I were, I would want a decoupling between my namespace hierarchy and my directory structure hierarchy. I like my directory hierarchies to be intuitive for getting to code I want to work with. To save myself from having to manually tell my autoloader the path to each file/class, I cache a couple of arrays in static variables that store just the file/class name in the one array and the folder path to the file in the other. After the cache (static vars) have been set on the first call to my function, it's just a matter of looking up in the filename array. For safety, and to be problem-free, no two php filenames should be identical across all of your directory hierarchy (your namespace)--I favor this practice anyways, and accordingly, I favor unique class names across my single namespace (despite it not yet explicitly defined). I did build in a check in my function to ensure all php file names/classes are unique.
3.) I converted many, many files that once had sets of functions in the global space to *abstract classes* that have private static variables and methods and of course also public static methods. So those sets of functions are now encapsulated in objects, and those objects are now auto-loaded. Simply for this benefit I will never again have a function in the global space other than my auto-loader function and other exceptions such as that.
4.) My auto-loader function uses only built-in php language constructs and operations and has no outside dependencies.
5.) If you utilize the function class_exists() in your codebase somewhere, realize that unless you are passing the second arg as false, you will trigger the autoloader to load that class. I stumbled on this of course. My use-case is that I don't want the class loaded: I only wanted to take some action if the class was being used (in an error-handler method).
6.) If you use the function method_exists(), you will definitely trigger the class to be loaded (which makes sense since you have already decided to drill down to looking for a specific method).
7.) I credit someone else's idea here: I also elected to call an init() method for the class being loaded should it exist. This saves me from having to manually call from the outside, let alone managing how and from where the call should be made. It is so useful to get your object set up and ready to do work in an automated fashion such as this.
8.) as another said, I also use require() and not require_once() as the first is enough to generate an error and if already loaded the function will not have been called.
9.) If for some reason I fail to find a class name in my cached arrays, I knowingly still call require(), passing the class name I had not accounted for in order to generate and reveal the problem (which of course is not anticipated!).
10.) Again, I ensure uniqueness across all class names. If I observe non-uniqueness, I again do a faulty call to require() like this: require('FoundMultiplesOfClassFile.php'); to reveal the problem. (I don't yet, and you likely should not, have any sophisticated error-handler registered so this is as good as anything else to me).