Вопрос: Есть ли обучающие материалы по ООП?

Лучший ответ:
Вот вам стог сена 
Вот вам тюк сена 
Какая между ними разница? И то, и то сено.
Но, тюк он компактный, его удобно складывать, его легко переносить, вы из него хоть домик постройте. Стог это такая...просто куча, с этой кучей не удобно работать, сыпется, раздувает ветром, переносить сложно, и домик не построишь. Кто знаком с сельской жизнью тот поймет)
Так вот, процедурный стиль, это стог сена, ООП это тюк сена. Процедурный стиль громоздкий, имеет огромную кучу каких то функции с длинными именами, его трудно поддерживать, вообще трудно вносить какие либо изменения, и если таковы понадобится, а сайт большой, то одно и то же изменение придется одинаково менять во многих местах, если вдруг вы где то забыли внести изменение то в лучшем случае это вызовет ошибку и вы её исправите, в худшем все продолжит работать но именно в том месте не так как надо, попробуйте потом найти это место...Что дает нам ООП...много чего, краткость кода, его ясность, его легко поддерживать, там нет повторяющегося кода, если вы что то захотите изменить, это нужно будет изменить единожды и ничего у вас не сломается после этого. 
Что касается примеров, этот пример должен быть большим что бы увидеть преимущества ООП подхода, это во первых, а во вторых преимущество особенно сильно проявляется когда вы работаете над этим проектом а не когда он уже написан и работает а вы смотрите на это со стороны.
Еще раз напомню чтоДа, кто-то скажет что это не имеет смысла, но всё же любопытно было бы сравнить.
вы что хотите сравнить? что красивше выглядит? кстати код написанный на ООП выглядит красивее и уже именно поэтому стоит его использовать)
Напомнить я хотел что не сравнивать его нужно, а работать с ним.
-----------------------------
Вот пример, который не покажет всех преимуществ, это лишь пример одного из многих преимуществ ООП. Задача такая, получить данные пользователя и вывести их на экран.Процедурный стиль:$q = $pdo->prepare("SELECT * FROM `users` WHERE `id` = ? LIMIT 1");
$q->execute([$id_user]);
$user = $q->fetch();
echo 'Имя: ' . $user['name'] . '<br />';
echo 'Фамилия: ' . $user['surname'] . '<br />';
echo 'Город: ' . $user['city'] . '<br />';ООП: class User{
    public $id;
    public $data;
    
    public function __construct(int $id)
    {
        $this->id = $id;
        $this->data = $this->getData();
        
    }
    private function getData(): array
    {
        $q = $pdo->prepare("SELECT * FROM `users` WHERE `id` = ? LIMIT 1");
        $q->execute([$this->id]);
        return $q->fetch();
    }
    public function __get($name)
    {
        if (isset($this->data[$name])) {
            return $this->data[$name];
        }
        return;
    }
}
$user = new User(1);
echo 'Имя: ' . $user->name . '<br />';
echo 'Фамилия: ' . $user->surname . '<br />';
echo 'Город: ' . $user->city . '<br />';
Казалось бы в чем тут преимущество если в ООП из данного примера больше кода, а выше я говорил о его краткости) краткость возникнет со временем при увеличении нашего приложения, еще я говорил что на ООП не любоваться нужно а работать с ним, так давайте же выполним следующие, сделаем так что если какие то данные не заполнены то выводилось сообщение "(данные не заполнены)"Процедурный стиль:$q = $pdo->prepare("SELECT * FROM `users` WHERE `id` = ? LIMIT 1");
$q->execute([$id_user]);
$user = $q->fetch();
echo 'Имя: ' . ($user['name'] ?? '(данные не заполнены)') . '<br />';
echo 'Фамилия: ' . ($user['surname'] ?? '(данные не заполнены)') . '<br />';
echo 'Город: ' . ($user['city'] ?? '(данные не заполнены)') . '<br />';ООП:class User{
    public $id;
    public $data;
    
    public function __construct(int $id)
    {
        $this->id = $id;
        $this->data = $this->getData();
        
    }
    private function getData(): array
    {
        $q = $pdo->prepare("SELECT * FROM `users` WHERE `id` = ? LIMIT 1");
        $q->execute([$this->id]);
        return $q->fetch();
    }
    public function __get($name)
    {
        if (isset($this->data[$name])) {
            return $this->data[$name];
        }
        return '(данные не заполнены)';
    }
}
$user = new User(1);
echo 'Имя: ' . $user->name . '<br />';
echo 'Фамилия: ' . $user->surname . '<br />';
echo 'Город: ' . $user->city . '<br />';
Вы заметили как изменился процедурный стиль? Нам пришлось изменять каждое поле, нам пришлось повторятся, и хорошо что у нас только три поля а не десятки, и хорошо что у нас то проект из одного файла а не из....многих. И еще очень хорошо что вышла PHP7, иначе пришлось городить еще кучу условий.
Вы заметили как изменился код ООП?
В одном месте изменился кусочек кода, было:return;
Стало:return '(данные не заполнены)';
Такие случаи будут появляться сплошь и рядом, поэтому выбор ООП подхода очевиден.
Еще более наглядно покажет преимущество ООП если мы добавим редактирование анкеты, в процедурном стиле нужно будет создавать три запроса (потому что в нашем примере три поля, в настоящем проекте их может быть десятки), в ООП придется один раз немного повозится (совсем чуть-чуть) и сделать универсальное обновление данных, что в результате, именно в том месте когда где потребуется обновление получится так:
Процедурный стиль:$q = $pdo->prepare("запрос");
$q->execute([/*переменная*/])
И так три раза (в нашем примере, а в реальном проекте больше)ООП:
нужно будет всего лишь написать так (например имя изменить)$user->name = 'новое имя';
Мы не просто свойство изменим, данные изменятся и в базе данных, всего лишь одной такой строкой, но как это сделать пусть будет домашним заданием, ибо уже три часа ночи и я пойду спать, всем добра)

Худший ответ:
php design patterns
в Гугл
https://github.com/domnikl/DesignPatternsPHP