Autoloading is pretty simple. PHP knows exactly where to look for code, and you know exactly where to look for it too. Class names are mapped exactly to file names [1], so autoloading lets you simply use a class without needing to explicitly include the file.

There's a number of issues inherent in manual include statements:

- When you include a file, unless you include it using the absolute path, the path will be resolved using the include_path ini setting, which works just like the $PATH environment variable works to resolve the location of binaries. Typically, `include_path` will be set to something like `/usr/share/php:.:/some/other/dir". If I encounter `require_once 'Foo/Bar.php';` in some code, what file will that include? `/usr/share/php/Foo/Bar.php`, but maybe also `./Foo/Bar.php`.

- Relative includes are relative to the current working directory, so a different file may be including (or not found at all) depending on what directory I'm executing my script from. To avoid this, it's good practice to include files using `include __DIR__ . '/Foo.php';` to ensure we know exactly what file is included.

- Prior to autoloading, most dependencies were installed in a global location, e.g. `/usr/share/php`, which would then be part of include_path. Different projects on the same machine therefore had to have the exact same dependencies. Autoloading enables per-project dependencies.

- Using manual includes makes it much easier to have a poorly structured project. With autoloading, if I see `$bar = new Foo\Bar();`, then I know exactly what I'm getting: the class Bar, defined in the file `src/Foo/Bar.php;`. On the other hand, if I see `include 'bar.php';`, I have no idea what I'm getting. What's in the file? Could be class, could be bunch of random functions, could be mish mash of HTML and PHP spaghetti.

Same of these issues are manageable even without autoloading by following best practices, but unfortunately there's a lot of really bad code out there that doesn't. Autoloading (along with composer) completely solves a problem that used to exist in PHP. Anyone that actually uses PHP can attest to this. If you've ever worked on a project with a web of manual includes, it's a total nightmare compared to a properly structured project using autoloading.

Autoloading aside, the point of this article, IMO, is that it's quite easy to set up a well structured, maintainable, easy to understand project architecture without using a major framework. The central abstraction here is that all requests go to a front-controller, which then calls a function that accepts a representation of the HTTP request and returns a representation of the response. Having abstractions for Request and Response is much more manageable (and testable!) than having random print statements everywhere and using global variables like $_POST. This is same idea behind just about all web programming "frameworks" in any language. Of course this would all be over kill if all you needed was a "Hello World" page. But this isn't about hello world pages, it's about real projects that grow over time and need manageable structure.

Furthermore, this article advocates for dependency injection. Again, overkill on a hello world page, but in a real project explicit dependencies makes life so much easier.

[1] This is the de-facto standard. Sure you could technically write an autoloader that does weird things, but nobody--human or automated tools--does this in real code. It's not a problem in practice--autoloading in the real world makes things much more explicit than manual includes.