Проектирование классов уровня обслуживания в PHP

Недавно я представил для обслуживания слоев Jani Hartikainen в обсуждении того, как лучше всего обрабатывать форму данных в приложении MVC. После делать некоторые чтения Я действительно могу видеть преимущества этого подхода. Мой вопрос таков:

Как структурировать классы служб?

  • Во-первых, user_service() соответствующее имя класса для моей модели user() или есть другой стандарт?
  • Так как методы в моей службе будут выполнять только одну задачу, правильно ли считать, что они всегда могут быть static function? Класс сервиса не представляет данные, а представляет собой ряд действий, поэтому это кажется уместным.
  • Если метод службы принимает только один argument, который будет array?

Рассмотрим, что форма отправила данные контроллеру для сохранения пользовательских данных:

<?php

    class form_controller extends controller
    {

        public function process_submit()
        {
            if(user_service::update_preferences($_POST))
            {

                echo json_encode(array('success' => true));
            }
            else
            {
                echo json_encode(array('success' => false));
            }
        }

    }

    class user_service
    {

        // Accepts array()
        public static function update_preferences($fields)
        {

            // Check for required fields
            if((
                isset($fields['firstname']) and
                isset($fields['lastname']) and
                isset($fields['email'])
                ) == false
            {
                return false;
            }

            // Update user
            try
            {
                $s = new user();
                $s->set_firstname($fields['firstname']);
                $s->set_lastname($fields['lastname']);
                $s->set_email($fields['email']);
                $s->update();

                return true;
            }
            catch(Exception $e)
            {
                return false;
            }
        }
    }

Я считаю, что это хороший подход, потому что:

  • Я могу добавить другое поле в свою форму, и мне не нужно будет обновлять controller, просто service. Кажется правильным, что контроллер не должен беспокоиться о том, какие данные передаются, просто передается. Это делает мой контроллер небольшим и логику в моих моделях.
  • Если я не передал array, я мог бы установить функции с несколькими аргументами. Например, моя функция может быть update_preferences($firstname, $lastname, $email). Это могло бы сделать для функций с 20 аргументами (для больших форм), и порядок просто стал бы ужасным для работы.
  • Я мог бы передать object, но имеет ли это смысл? Если я создаю объект, это должен быть объект, который он представляет (пользователь в этом случае), правильно? Но имеет ли смысл, что контроллер создает экземпляр объекта пользователя? Разве это не все, что касается уровня обслуживания?
  • Может быть, есть аргумент для наличия некоторых методов с несколькими аргументами (когда их всего один-три) и некоторых методов, которые принимают массив (когда есть много полей). Это похоже на то, что это может быть кошмар, так как вам всегда нужно будет ссылаться на класс, чтобы узнать, что просил этот конкретный метод.

Есть ли у кого-нибудь мнение о том, что нужно делать здесь? Я на правильном пути? Что вы делали в прошлом? Большое спасибо!

Ответы

Ответ 1

Можно также ответить на этот вопрос, так как вы отправили мне письмо по электронной почте;)

Во-первых, это user_service() соответствующее имя класса для моей модели user() или есть другой стандарт?

Это приемлемо. Тем не менее, вы должны использовать один из установленных правил кодирования PHP, например соглашения PEAR или ZF. В обоих случаях имена классов UpperCamelCase и имена методов lowerCamelCase. Используя это, классы будут User и UserService

Так как методы в моей службе будут выполнять только одну задачу, правильно ли считать, что они всегда могут быть статической функцией? Класс обслуживания не представляет данные, а представляет собой ряд действий, поэтому это кажется подходящим.

Нет. Это плохой выбор дизайна, чтобы сделать методы статическими - и это касается большинства кодов, а не только сервисов. Одной из основных причин в случае службы является то, что обычно вашему сервису необходимо взаимодействовать с хранилищем данных или другим классом, который представляет собой уровень данных (репозиторий, объект доступа к данным и т.д.).

Если у вашего сервиса есть статические методы, это означает, что вам нужно будет управлять вашими зависимостями в ваших методах. Это, в свою очередь, означает, что, помимо прочего, код становится трудно тестировать, поскольку вы не можете легко заменить зависимости.

Там есть хорошее чтение этого, например здесь (На самом деле почти все, что на этом блоге хорошо читает для разработчиков программного обеспечения)

Если метод службы принимает только один аргумент, который будет массивом?

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

Я могу добавить еще одно поле в свою форму, и мне не нужно будет обновлять контроллер, просто службу. [...]

Если я не передал массив, я мог бы настроить функции с несколькими аргументами. [...]

Да, ваша аргументация по этим двум случаям очень важна для этого случая использования, на мой взгляд.

Я мог передать объект, но имеет ли это смысл? Если я создаю объект, это должен быть объект, который он представляет (пользователь в этом случае), правильно? Но имеет ли смысл, что контроллер создает экземпляр объекта пользователя? Разве это не все, что касается уровня обслуживания?

Это зависит. Например, если вы использовали фреймворк, который позволяет представлять формы как объекты (такие как Zend Framework и Zend_Form), вы можете рассмотреть возможность передачи форма объекта прямо к сервису.

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

Обычно вы должны стремиться к тому, чтобы параметры были, по меньшей мере, полузагадываемы, основываясь на имени метода. В что-то, над чем я работаю, у нас есть модель, которая имеет, например, предприятия и продукты, где бизнес может спонсировать продукт. В ProductService мы имеем метод под названием sponsorProduct, который принимает бизнес и продукт в качестве параметров. Вы вполне можете догадаться, что это возьмут эти два (если вы все равно знакомы с кодовой базой)

IDE обычно помогает вам в этом - они предоставляют код-помощь, которая отображает функции параметров. Это одна из основных причин, по которой я считаю, что IDE очень полезна в более крупных проектах, где вы не всегда можете вспомнить, что именно требуется определенной функции в качестве параметров.

Что касается количества параметров, я думаю, что обычно вы должны пытаться иметь отдельные параметры. Это позволяет любому легко видеть, какие параметры требуются, просто глядя на подпись функции, и позволяет легко определить типы и значения по умолчанию.

Однако есть момент, когда вы так много получаете параметров. Это может быть при +5 или около того, в зависимости от того, какой метод он есть. В этом случае вы можете рассмотреть использование массива или что-то вроде объекта параметров, который по существу является объектом, который содержит все параметры для вызова. Подробнее об объектах параметров здесь