Этот урок набрал набрал достаточно большое количество комментариев и дальнейшее его комментирование отключено. Если вы хотели убедиться в правильности выполнения ДЗ или у вас возник вопрос по уроку, посмотрите ранее добавленные комментарии, кликнув по кнопке ниже. Скорее всего вы найдете там то, что искали. Если это не помогло - задайте вопрос в чате в телеграме - https://t.me/php_zone
Galay 27.07.2018 в 13:16

Итак, с первым пунктом про хранение классов в отдельных классах мы разобрались.

Наверно имеловь ввиду "хранение классов в отдельных папках"?

ivashkevich 28.07.2018 в 06:44

В отдельных файлах. Спасибо, исправил =)

Sparkqy 31.08.2018 в 14:45

описание картинки
при автозагрузке классов возникает ошибка. Не подключаются неймспейсы, как пофиксить? Код идентичный вашему, я так понимаю проблема в "\" слешах.

Sparkqy 31.08.2018 в 14:54

Код ошибки:

Warning: require_once(/var/www/html/php-learn/Sparky-project/www/../src/MyProject\Models\Users\User.php): failed to open stream: No such file or directory in /var/www/html/php-learn/Sparky-project/www/index.php on line 11

Fatal error: require_once(): Failed opening required '/var/www/html/php-learn/Sparky-project/www/../src/MyProject\Models\Users\User.php' (include_path='.:/usr/share/php') in /var/www/html/php-learn/Sparky-project/www/index.php on line 11
Sparkqy 01.09.2018 в 10:13

окей, помощи особо не вижу, пофиксил сам. Заменил обратные слеши через str_replace, таким образом путь стал правильным

ivashkevich 01.09.2018 в 13:42

Да, всё дело именно в них. Разница в том, что я писал урок под виндой, а там в путях как раз обратные слэши. Ваше решение с использованием str_replace - в самый раз.

Tina 25.06.2019 в 00:53

А говорите Иван что за 2 года не было такой проблемы с которой сталкиваются маководы

ivashkevich 25.06.2019 в 04:39

Так вы про это ничего не говорили.
P.S. я не Иван

[email protected] 30.09.2019 в 21:50

Кто же ты,тайный незнакомец)

ivashkevich 01.10.2019 в 09:08

Кек)

Benya 30.09.2018 в 18:57

Та же проблема что у Sparky, что то до конца не понял как ее решить?

den 01.10.2018 в 11:33

Достаточно просто так:

require_once __DIR__ . '/../src/' . str_replace('\\', '/', $className) . '.php';
ivashkevich 02.10.2018 в 21:42

Спасибо что подменили меня =)

VladimirTitov 23.11.2019 в 10:43

Я вот на линуксе пробую прописать namespace MyProject/Models/Articles;

чтобы не менять слеши, но IDE ругается. Так как верно назвать namespace на UNIX ?

artemjeka 12.10.2018 в 08:29

Не разобрался с ошибкой:

Fatal error: Uncaught Error: Class 'models\articles\Article' not found in /namespaces/public_html/index.php on line 18

var_dump();

/namespaces/public_html/index.php:11:string 'models\articles\Article' (length=23)
/namespaces/public_html/index.php:12:string '/namespaces/public_html/../src/models/articles/Article.php' (length=125)

PS У меня только нет папки MyProject и все папки маленькими буквами.

ivashkevich 12.10.2018 в 08:47

Если еще актуально - напиши в личку.

artemjeka 12.10.2018 в 09:00

Нет, только что понял свой косяк.

artemjeka 12.10.2018 в 09:03

Дело в том, что я указал:

namespace models\articles\Article;
namespace models\users\User;

А надо было просто путь до класса без самого класса:

namespace models\articles;
namespace models\users;
ivashkevich 12.10.2018 в 09:11

Нэймспейсы должны быть с большой буквы, это стандарт PSR-4. Чуть позже о нем расскажу.

artemjeka 12.10.2018 в 09:15

Получается и папки в src тоже...

ivashkevich 12.10.2018 в 09:17

Да. А зачем не по урокам делали?

artemjeka 12.10.2018 в 10:07

А я сразу думал разобрать, что да как, своими руками писал. Время много положил на это правда.

artemjeka 12.10.2018 в 09:09

Еще оформительский вопрос остался.
Как правильнее обращаться к классу при создании объекта?
В документации http://php.net/manual/ru/language.namespaces.rationale.php
внизу, в дополнении кто-то написал якобы по PSR стандарту:

<?php $tool = new Pierstoval\Tools\MyTool(); ?>
  • то есть без корневого слеша.
ivashkevich 12.10.2018 в 09:12

Можно и полный неймспейс указывать, а можно через use в начале файла. Второй вариант предпочтительнее.

artemjeka 12.10.2018 в 09:17

Я извиняюсь, вопрос был о дотошном перфекционизме как правильнее):

$tool = new Pierstoval\Tools\MyTool();

или

$tool = new \Pierstoval\Tools\MyTool();

Я так понял с корневым \ - более универсально использовать.

ivashkevich 13.10.2018 в 21:14

С корневым правильно. Можете прочитать про PSR-4.

artemjeka 12.10.2018 в 09:43

Что-то я не понимаю почему у меня нет ошибки как в этом уроке когда надо добавить в Article.php

public function __construct(string $title, string $text, \MyProject\Models\Users\User $author)

и

public function getAuthor(): \MyProject\Models\Users\User

У меня без явного определения пространства имен отрабатывается код::

{path}/namespaces/public_html/index.php:20:
object(Models\Users\User)[1]
  private 'name' => string 'Иван' (length=8)
{path}/namespaces/public_html/index.php:21:
object(Models\Articles\Article)[2]
  private 'title' => string 'Заголовок' (length=18)
  private 'text' => string 'Текст' (length=10)
  private 'author' => 
    object(Models\Users\User)[1]
      private 'name' => string 'Иван' (length=8)

Все, обнаружил свой косяк: не поставил тип переменной User для переменной $author в Article.php.
Это я так понимаю чтобы автором статьи не мог стать кто-то отличный от User (например кот или пес))

ivashkevich 13.10.2018 в 21:15

Да, Вы всё верно поняли)

virtual2018 24.12.2018 в 10:19

Я правильно понимаю, что мы здесь пишем конструкции вида:

<index.php>
$author = new \MyProject\Models\Users\User('Иван');
$article = new \MyProject\Models\Articles\Article('Заголовок', 'Текст', $author);

для наглядности? В реальной программе с большим количеством кода, лучше использовать псевдонимы и тогда будет меньше таких устрашающе длинных строк:

<?php

use MyProject\Models\Users\User as UserAlias;
use MyProject\Models\Articles\Article as ArticleAlias;

function myAutoLoader(string $className)
{
    var_dump($className);
    require_once __DIR__ . '/../src/' . $className . '.php';
}

spl_autoload_register('myAutoLoader');

$author = new UserAlias('Иван');
$article = new ArticleAlias('Заголовок', 'Текст', $author);
ivashkevich 24.12.2018 в 19:08

Вообще без псевдонимов, просто use. Но об этом дальше.

landialog 04.01.2019 в 20:18

Решение c заменой слешов есть в комментах и оно рабочее. Но как тогда будет код выглядеть на Linux если не использовать ф-ю str_replace (замену слешов)?

require_once __DIR__ . '/../src/' . $className . '.php';

И спасибо за урок, пока поковырялся воспроизвести тоже самое, пришло понимание как это должно работать.

ivashkevich 05.01.2019 в 07:58

Для линукса обычная косая черта в путях используется.

landialog 05.01.2019 в 11:26

может что-то я неправильно делаю, но я пробую устанавливать в таком виде: require_once __DIR__ . '\..\src\' . $className . '.php'; и PhpStorm выдает ошибку в результате ничего не работает

ivashkevich 05.01.2019 в 11:38

Ну так а чего слэши обратные?

landialog 05.01.2019 в 12:48

Подскажите лучше сразу правильный вариант, иначе я не догоню. Я месяц как перешёл на Линукс и для меня не все иногда понятно :)

ivashkevich 05.01.2019 в 12:51

Правильный вариант в уроке приведен. Там слэши в другую сторону.

Waldemar 14.01.2019 в 10:23

"Добавим var_dump() с выводом переменной $className." - добавил, не сработало, не вывелась информация по именам классов, т.е. всё осталось без изменений.

object(MyProject\Models\Articles\Article)[2]
  private 'title' => string 'Заголовок' (length=18)
  private 'text' => string 'Текст' (length=10)
  private 'author' => 
    object(MyProject\Models\Users\User)[1]
      private 'name' => string 'Иван' (length=8)
ivashkevich 16.01.2019 в 09:06

А подключения файлов убрали в самом начале?

AxLT 02.02.2019 в 01:27

Вот такой вопрос появился. При подключении файлов:

function myAutoLoader(string $className)
{
    var_dump($className);
    require_once __DIR__ . '/../src/' . $className . '.php';
}

Мы получаем из $className путь с обратными слешами

string 'MyProject\Models\Users\User' (length=20)

и если подставить то что мы получили к require_once то выходит:

require_once __DIR__ . '/../src/MyProject\Models\Users\User.php' //как это работает то?)
ivashkevich 02.02.2019 в 03:02

Почитайте комментарии)

fosfat 29.08.2019 в 03:57

Прочитал все комментарии, но прямого ответа на вопрос человека выше не нашел. Есть просто комменты про решение проблемы обратного слеша у пользователей на Маке.

Поэтому присоединюсь: как это работает, что мы соединяем "стандартные" слеши в пути с обратными слешами? Почему не возникает конфликта?

ivashkevich 29.08.2019 в 06:13

Потому что это винда и ей плевать на наклон слеша)

Art 17.05.2019 в 10:38

Доброе утро! Не совсем очевидно, как упаковывать дочерние и родительские КЛАССЫ относительно друг друга в файловой системе, и как должны при этом формироваться неймсппейсы в соответствии с psr-4?

Так же не понятно, как в таком случае поступать с трейтами и интерфейсами, по идее их также нужно упаковывать в отдельные файлы?

ivashkevich 17.05.2019 в 21:51

Каждый класс, интерфейс или трейт должен лежать в отдельном файле. Имя файла должно совпадать с его именем. Касательно того, как должны выстраиваться неймспейсы - тут нет однозначного ответа, все зависит от бизнес-логики и инфраструктуры проекта.

Art 21.05.2019 в 13:48

Артем, спасибо, принято!)

Danya 04.06.2019 в 07:27

spl_autoload_register - Регистрирует заданную функцию в качестве реализации метода __autoload(). , которая загружает все неопределенные классы , я все верно понял ?)

ivashkevich 06.06.2019 в 09:27

Да. Только с помощью spl_autoload_register можно добавить несколько функций автозагрузки.

Danya 07.06.2019 в 01:23

то есть несколько аргуметов в этой функции?

ivashkevich 07.06.2019 в 12:26

Нет. Несколько разных функций. Почитайте документацию.

Invo 29.06.2019 в 20:13

_autoload() - использовать нынче кощунство, все вокруг говорят что устарело и не стоит этого делать...

Danya 09.07.2019 в 22:29

Я не совсем понял как и где мы заполняем $classname , он только вызывается в качестве аргумента , а где мы пишем $classname = путь к нужным классам. Как это работает?

Я имею ввиду вот функция , а где мы пишем $classname = путь к файлу с классом? Он что телепат и сам понимает где файлы с классами лежат =)

spl_autoload_register(function (string $className) {
    require_once __DIR__ . '/../src/' . $className . '.php';
});

А то тут неясные для меня действа происходят, объясните пожалуйста

ivashkevich 12.07.2019 в 05:24

Зачем же телепат) Когда в коде встречается имя какого-то неизвестного класса, происходит вызов функции, которую мы зарегистрировали через spl_autoload_register. И в качестве аргумента передается имя вот этого неизвестного нам класса. И всё)

Iliusha99 20.07.2019 в 17:59

На примере класса User это будет выглядеть следующим образом:
src/MyProject/Models/Users/User.php :

namespace MyProject\Models\Articles;

Почему начинаем именно с MyProject а не с src, как правильно путь прописать в неймспейсах, или можно любые пути прописать?

ivashkevich 21.07.2019 в 05:29

src это просто папка, в которой хранится весь наш код. Внутри нее есть код с неймспейсами, в частности, начинающийся с MyProject...

Iliusha99 21.07.2019 в 10:20

Да но, Models тоже папка, почему не начинаем с Models чтобы понятнее было что работаем с моделями, или чтобы лучше структурировать пути кода в проекте?

ivashkevich 21.07.2019 в 14:26

Понял теперь твой вопрос. Это делается, чтобы отделить код проекта от кода подключаемых библиотек (об этом будет дальше). Код проекта выделяется в отдельный неймспейс с названием проекта. Наш учебный проект называется MyProject, отсюда и начало неймспейса. Для Фейсбука неймспейс начинается с Facebook\...

Iliusha99 21.07.2019 в 14:37

Ясно, спасибо

uzabila 10.09.2019 в 15:36

Прошу простить за вопрос, но хочется на старте понять правильность дерева папок.

У нас есть условный домен "myproject.loc", а в нем есть папки "src" и "www". При этом файл index.php только в папке "www", так?

Т.е. для запуска скрипта мы должны именно ввести в адресной строке "myproject.loc/www/index.php"?
А если просто попробовать открыть myproject.loc при запущенном OpenServer ничего не произойдет? Или в корне будет еще один index.php? Вопрос еще с точки зрения последующего переноса проекта на хостинг, когда ты будешь просто вводить в браузере имя домена.

Спасибо заранее.

ivashkevich 10.09.2019 в 20:52

Т.е. для запуска скрипта мы должны именно ввести в адресной строке "myproject.loc/www/index.php"?

Нет. В адресной строке должно быть myproject.loc

www - это корневая папка для веб-сервера, но не для всего проекта. Для этого нужно соответствующим образом настроить OpenServer. Смотрите урок об этом в курсе PHP для начинающих. На хостинге эта папка в большинстве случаев именуется public_html.

Что касается index.php, то он зарезолвится с помощью правил в .htaccess

uzabila 10.09.2019 в 22:59

Понял! Спасибо :)

vtolstov 19.09.2019 в 07:36

Нашел еще хорошую статью по неймспейсам и автозагрузке. Может кому пригодится для расширения данного урока: https://github.com/codedokode/pasta/blob/master/php/autoload.md

[email protected] 04.10.2019 в 22:45

Странно,не работает автозагрузка через spl_autoload_register ,хотя пишет failed to open stream: No such file or directory,но показывает путь точно до нужного файла.

ivashkevich 05.10.2019 в 00:06

Linux?

[email protected] 05.10.2019 в 16:59

Да,я уже пофиксил)

[email protected] 12.10.2019 в 12:45

Как в переменную $className попадает неймспейс класса,который мы хотим подключить,это магия? p.s остальное всё понял.

ivashkevich 12.10.2019 в 12:52

Когда встречается не используемый ранее класс, вызывается эта функция, в аргумент прилетает полное имя класса, включая неймспейс. И да, это магия.

[email protected] 12.10.2019 в 13:15

Это я понял,я не понял,как до аргумента долетает полное имя класса,включая неймспейс,это из-за spl_autoload_register ?

ivashkevich 12.10.2019 в 13:28

Да

OneMoreTime 29.04.2020 в 23:42

www - это корневая папка для веб-сервера, но не для всего проекта.

Если www - корень веб-сервера, myproject.loc - корень проекта? Корень веб-сервера = корень сайта? Что есть папка - MyProject? Просто структурированный каталог рабочих файлов для сайта?

Если начинать с myproject.loc, то на реальном сервере наверное нужно себе представлять наличие папки domains(проект === домен?), а внутри нее уже должно лежать содержимое myproject.loc и все остальное? А если нет на сервере папки domains, то должна быть папка www или public_html, а на одном уровне с этой папки уже должна быть папка src?

И какое место в этой смысловой иерархии занимает папка src? Это тоже корень чего то?
Как - то не получается мысленно перенести предложенную структуру с локального сервера на реальный. Где - корень чего. Смотрел структуры каталогов и файлов у разных хостеров - везде все по разному.

ivashkevich 30.04.2020 в 11:12

myproject.loc - корень проекта
www (public_html) - корневая директория сайта в рамках веб-сервера
src - тут все исходники для бэкенда, кроме фронт-контроллера, лежащего в www
MyProject - домен проекта, тут непосредственно код проекта, без всей вспомогательной шелухи

[email protected] 29.04.2020 в 23:53

выходит ошибка

Warning: require(C:\Abyss Web Server\htdocs\ООП\MyProject.loc/.../src/Models/Users/User.php): failed to open stream: No such file or directory in C:\Abyss Web Server\htdocs\ООП\MyProject.loc\index.php on line 3

Fatal error: require(): Failed opening required 'C:\Abyss Web Server\htdocs\ООП\MyProject.loc/.../src/Models/Users/User.php' (include_path='.;C:\php\pear') in C:\Abyss Web Server\htdocs\ООП\MyProject.loc\index.php on line 3

сам код

<?php

    require __DIR__.'/.../src/Models/Users/User.php';
    require __DIR__.'/.../src/Models/Articles/Article.php';

    $author = new User('Eldar');
    $article = new Article('Заголовок','Текст',$author);
    var_dump($article);

Я понял свою ошибку, мне не надо было набирать '/...'. Как только убрал, норм стало
Папку MyProject уже создал, просто забыл создать

ivashkevich 30.04.2020 в 11:14

Почему у вас фронт-контроллер лежит в одной директории с src? Делайте как было в уроке изначально.
И откуда три точки взяли?

[email protected] 30.04.2020 в 14:51

Что за фронт-контроллер?
Оу, только сейчас заметил, что их две :<

[email protected] 30.04.2020 в 15:28

я так и не понял, что такое фронт-контроллер,но исправил ошибки:
1)в директории с папкой src создал папку www, в эту папку поместил файл с кодом
2)вернул '/..', теперь не три, а две точки :>
всё работает :D

ivashkevich 30.04.2020 в 19:09

Фронт-контроллер - это точка входа в приложение. В нашем случае это index.php в папке www

[email protected] 30.04.2020 в 19:16

Спасибо )))

Sviatoslav 24.05.2020 в 16:57

В синтаксисе namespace присутствует бэкслеш. В убунту при создании функции автозагрузки php ругается на бэкслеши в пути к файлу с классом. Данная проблема решается при помощи функции str_replace.
У меня вопрос. Функцию str_replace нужно применять по умолчанию при создание автозагрузки классов с namespace? Или это просто "костыль" ?

ivashkevich 24.05.2020 в 20:43

Привет. Нужно применять

IePyton 01.06.2020 в 17:17

Я тоже с мака, и тоже возникла проблема со слешами.
Вопрос, если мы заменяем слеши функцией str_replace('\', '/', $className) при работе на маке на локалке. После загрузки на боевой сервак - будет ли все работать?

ivashkevich 01.06.2020 в 20:32

Да, там тоже unix

superbobr 12.06.2020 в 16:11

"Вот такими вот нехитрыми действиями мы сделали автозагрузку классов. PHP – прекрасный язык, не правда ли?"

Не уверен, после Python он мне кажется ужасным :)

ivashkevich 13.06.2020 в 09:01

Зачем же вы его тогда изучаете?)

superbobr 13.06.2020 в 09:49

Да нет, без обид, многим Python с его отступами после PHP кажется ужасным, так что извиняюсь если что не так сказал ;)
Пробую изучать потому-что работы, в смысле вакансий для джунов, да и на фрилансе на пыхе раз в пять больше предложений. Wordpress нравится еще, понятно на чем он написан. Но к примеру в Python - self, а тут и self и this... Опять же эта тема, я толком Python еще не изучил, но там вроде import и проще все. Хотя в PHP уже есть возможность сделать строгую типизацию...
А Python я толком не освоил, а теперь PHP, все в голове перемешалось :) Попробую на Javascript еще нажать, та вроде бы есть, как мне на первый взгляд показалось общие черты с Питоном... Потому как одного Python для веба мало, а для серьезных тем у меня с математикой слабо.
Но никого не хотел зацепить, беру свои слова обратно :) PHP прекрасный язык, как и Python :) Просто я не могу уместить их вместе в своих мозгах :)

ivashkevich 13.06.2020 в 12:23

Не стоит изучать 3 языка сразу, плохая идея) Вряд ли изучите даже один при таком раскладе.

superbobr 13.06.2020 в 15:37

Спасибо, я уже это понял :) Но опять же в вебе никуда без HTML, CSS, не языки, но тоже требуют изучения. И желательно Javascript, как это все вместить в одну голову :)

[email protected] 30.06.2020 в 23:38

Спасибо, Артем, за очередной урок.
Хочу уточнить момент.

Вы в комментариях пишите, что винде все равно какие слеши указаны в пути... То есть, например, пользователь с Виндой сможет работать с сайтом, где пути написаны в обратным слешем, а пользователь Мака, например, не сможет?

ivashkevich 01.07.2020 в 18:23

Всё так

[email protected] 01.07.2020 в 22:19

Значит str_replace за правило.

ivashkevich 02.07.2020 в 08:09

Ага)

[email protected] 13.11.2020 в 03:30

Если чЁ, даю конечный код в файле index.php для страждущих:

use MyProject\Models\Users\User;
use MyProject\Models\Articles\Article;

/*Вы заметили, что мы одинаково называли папки, в которых лежат файлы и нейсмспейсы классов? Это мы делали не просто так, а для того, чтобы можно было преобразовать полное имя класса (включая его неймспейс) в путь до .php-файла с этим классом.*/

spl_autoload_register( static function (string $class) {
    $class = str_replace('\\', '/', $class); //В операционной системе Windows используются обратные слеши, а в операционной системе Linux используются прямые слеши. И операционная система Windows прекрасно понимает оба варианта, но для Linux важны прямые слеши. Если код запустить на Linux, на котором работают большинство серверов, то у нас ничего работать не будет. Напишем функцию, мы ищем обратные слеши и заменяем их на прямые

    $file = __DIR__ . '/src/' .$class. '.php'; //Можем посмотреть путь если перед переменной $file добавить echo. Имя класса преобразуется в путь.

    //Проверка: существует ли файл по указанному пути
    if (file_exists($file)) { //Мои комменты - Без этого условия код будет работать, но лучше его оставить
        require_once $file;
    }
});

$author = new User('Иван');
$article = new Article('Заголовок', 'Текст', $author);
var_dump($article);
Forcket 20.11.2020 в 15:35

Извините, уточнение:
<?php

namespace MyProject\Models\Articles;

use MyProject\Models\Users\User;
use MyProject\Models\Admins\Admin;

class Article
{
private $title;
private $text;
private $author;

public function __construct(string $title,  Admin $text, User $author)
{
    $this->title = $title;
    $this->text = $text;
    $this->author = $author;    
}

public function getTitle() : string
{
    return $this->title;
}

public function getText() : Admin
{
    return $this->text;
}

public function getAuthor() : User
{
    return $this->author;
}

}

Добавил еще один файл и в нем класс, для проверки и понимания автозагрузки. Я правильно понимаю, то что порядок в обозначениях в private должно быть точно такое же, как и в construct? Так же, как и в скобках в construct? Верно?

ivashkevich 23.11.2020 в 17:30

Нужно оформить код в комментарии (в редакторе комментариев самая первая кнопка).
Нажмите на карандашик и поправьте ваш комментарий, пожалуйста. А потом ответьте мне на этот комментарий. После этого проверю вашу домашнюю работу и отвечу на вопросы.

dimadima 10.03.2021 в 20:37

описание картинки
Почитав комментарии понял, что вход через http://localhost/www/index.php не верен, а если просто localhost, то выдает вот это непонятное.

ivashkevich 12.03.2021 в 08:10

Привет. А какой у тебя веб-сервер?

dimadima 22.03.2021 в 18:12

Open Server, версия PHP в нем 7.1

ivashkevich 26.03.2021 в 17:31

Настрой его по уроку из курса для начинающих. У тебя не localhost должен быть, а myproject.loc

Deo 21.03.2021 в 18:08

У меня рядом с index.php ещё остаются файлы с прошло курса (login, upload, feedback, calculator) и папка uploads, а так же папка private рядом с public_html - их тоже в перспективе нужно переместить в src?
Я попробовал - из src не удалось получить иконки фоток и стили css, остальные файлы подключились правильно...

ivashkevich 26.03.2021 в 17:30

Лучше отдельный проект завести)

Deo 26.03.2021 в 18:16

А фотки то почему не отображаются как иконки, когда папка uploads перенесена в src (пути соответственно переписаны)?
И стили не подключаются из src - почему?
...
Опять сам нашёл - потому что папка src (зачем-то(?)) выведена из корневой папки сайта...

ivashkevich 04.04.2021 в 16:10

Всё, что должно грузиться браузером (картинки, стили, js) должно лежать в www.

Логические задачи с собеседований