One of the questions beginners in OOP might ask is whether it is better to have one big class or several smaller ones. This is actually very easy to answer. The clear winner is multiple smaller classes in nearly all situations. But, it really depends on how these classes are instantiated.
If you just have one big class, it will get extremely hard to maintain as your project grows. Scrolling up and down to find things can take quite a while, and I personally find, even when working with small classes (below 1000 lines), scrolling sometimes disrupts my flow a lot, especially if I am tired or frustrated about some problem I am trying to solve.
You can of course still use the search function in your editor to quickly find what you are looking for, which does eliminate some of the need to scroll. But, even when searching, I am still wasting a significant amount of time on looking for things.
Having smaller classes helps tremendously with this problem, and it also helps you write code that is more flexible.
When you are using multiple classes, you should really think about your directory structure.
In my own projects, I like to have a directory in the root called lib. Inside of this directory I have subdirectories for my objects (classes). I have one subdirectory for each object, which might consist of several classes.
The reason I stick to one subdirectory per object, even when I only got a single class in the directory, is, at some point this class might grow, at which point I might decide to split the class into several smaller ones.
It is often hard to know how many classes you will have before hand, so I will typically just start out with one class, and then split it when I find it makes logical sense.
For inspiration, look at this hypothetical example structure:
Note. Templates is also commonly named "views". This directory typically contain HTML templates and CSS files for a website.
Part of the process in creating your application architecture is to create a suitable directory structure, as well as choosing a design pattern to follow. This may seem intimidating at first, but is actually not that hard, and very often it is a process, so do not expect your architecture to be perfect from the start.
A common design pattern for web applications is MVC (Model-View-Controller).
However, even without following a design pattern, a very basic principle, which will almost force you to think in patterns without thinking much about it, is the Don't Repeat Yourself (DRY) principle. This principle is simply about avoiding repeating yourself in code. In other words, instead of writing the same code over and over, you create a function (Method in a class) that can be called whenever needed.
Multiple classes and code reusability
As your project grows, you will probably start to split your classes into multiple classes. Both because this makes it easier to maintain your code, and because it makes it easier to reuse code in other projects or places. At this point you might have a class that outputs your HTML, and another class that connects to your database. Etc.
When you have worked with multiple classes for awhile, you might also realize that dependency injection (DI) is better then class extends, since it allows you to instantiate your classes independently, without having to also instantiate irrelevant child classes that might not be needed.
The reason you should avoid class extends is, when you have classes that are extended, they tend to loose their flexibility, and you will not be able to easily use them separately. Instead, you can simply create a "factory" class to "build" your objects with all of their dependencies.
Another reason to avoid extends is, instantiation gets confusing with extends. You need to name your files in a specific way to know which file/class the object should be instantiated from, which again makes you loose flexibility when naming files or when using an autoloader that requires file names to match class names.
Avoiding the new keyword inside classes
You should nearly always avoid instantiating objects inside other object. Meaning, you should avoid using the new keyword inside other classes–except for your within your factory classes, which are used to instantiate all the required classes, and pass them on where needed.
Completed objects, as in objects made from multiple classes, can either be "build" from your composition root (I.e. index.php), or you can use a factory class to make the objects. It makes sense to have factories that instantiate objects when you have multiple classes with lots of dependencies, because this makes it more clear what exactly is needed to build a certain object.
Using factories is useful when writing loosely coupled code that is very flexible and easy to reuse.