用PHP设计服务层类 [英] Designing service layer classes in PHP

查看:101
本文介绍了用PHP设计服务层类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近被介绍 Jani Hartikainen 讨论了如何在MVC应用程序中最好地处理表单数据.在做些阅读之后我真的可以看到这种方法的好处.我的问题是这样:

I was recently introduced to service layers by Jani Hartikainen in a discussion about how to best handle form data in a MVC app. After doing some reading I can really see the benefits of this approach. My question is this:

服务类应如何构建?

  • 首先,user_service()是我的user()模型的合适的类名还是其他标准?
  • 由于我服务中的方法只能执行一项任务,因此认为这些方法始终可以是static function是否正确?服务类不是表示数据,而是一系列动作,因此这似乎是适当的.
  • 服务方法应只接受一个argument,即一个array吗?
  • First, is user_service() an appropriate class name for my user() model or is there another standard?
  • Since the methods in my service will only be doing one task, is it correct to think that these can always be a static function? A service class isn't representing data, but rather is a series a actions, so this seems appropriate.
  • Should a service method only accept one argument, which would be an 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,但这有意义吗?如果我要创建一个对象,它应该是它代表的对象(在这种情况下为用户),对吗?但是,控制器实例化用户对象是否有意义?那不是服务层的全部要点吗?
  • 也许有一个参数,它包含一些带有多个参数的方法(当只有一到三个时)和一些接受数组的方法(当有很多字段时).这似乎是一场噩梦,因为您总是必须引用该类才能知道特定方法的要求.
  • I can add another field to my form and I won't have to update the controller, just the service. It seems right that the controller shouldn't be concerned about what data is being passed, just that it is passed. This keeps my controller small, and the logic in my models.
  • If I didn't pass an array, I could setup functions with multiple arguments. For example my function could be update_preferences($firstname, $lastname, $email). This however could make for functions with upwards of 20 arguments (for large forms), and the order would just become terrible to work with.
  • I could pass an object, but does that make sense? If I'm creating an object, it should the be the object it represents (the user in this case) right? But does it make sense that the controller instantiates the user object? Isn't that the whole point of the service layer in the first place?
  • Maybe there is an argument for having some methods with multiple arguments (when there are just one to three) and some methods that accept an array (when there are lots of fields). This just seems like it could be a nightmare, as you would always have to reference the class to know what that particular method was asking for.

有人对这里做对的事情有意见吗?我在正确的轨道上吗?你过去做什么?非常感谢!

Does anyone have an opinion on what the right thing to do here is? Am I on the right track? What have you done in the past? Thanks a lot!

推荐答案

也可以回答这个问题,因为您可能会给我发送电子邮件;)

Might as well answer this since you went as far as sending me an email ;)

首先,user_service()是适合我的user()模型的类名吗?还是有其他标准?

First, is user_service() an appropriate class name for my user() model or is there another standard?

这是可以接受的.但是,您应该使用已建立的PHP编码约定之一,例如PEAR或ZF约定.在这两种情况下,类名称均为UpperCamelCase,方法名称为lowerCamelCase.使用此类将是UserUserService

That's acceptable. However, you should rather use one of the established PHP coding conventions, such as the PEAR or ZF conventions. In both cases, class names are UpperCamelCase and method names lowerCamelCase. Using this, the classes would be User and UserService

由于我的服务中的方法只能执行一项任务,因此认为这些方法始终可以是静态函数是否正确?服务类不是表示数据,而是一系列动作,因此这似乎是适当的.

Since the methods in my service will only be doing one task, is it correct to think that these can always be a static function? A service class isn't representing data, but rather is a series a actions, so this seems appropriate.

不.使方法静态化是一个糟糕的设计选择-这适用于大多数代码,而不仅仅是服务.使用服务的主要原因之一是,通常您的服务需要与数据存储或代表数据层(存储库,数据访问对象等)的其他类进行交互.

No. It's a poor design choice to make methods static - and this applies to most code, not just services. One of the main reasons in case of a service would be that generally your service needs to interact with a data store or another class which represents the data layer (repository, data access object, whatever).

当服务具有静态方法时,这意味着您需要实例化方法中的依赖项.反过来,这意味着除其他事项外,由于您无法轻松替换依赖项,因此代码变得难以测试.

When your service has static methods, this means you would need to instanciate your dependencies in your methods. This in turn means that, amongst other things, the code becomes hard to test, as you can't easily replace the dependencies.

例如,这里(实际上,该博客上的几乎所有内容对于软件开发人员来说都是不错的选择)

There's some good reading on this for example here (In fact nearly everything on that blog is good reading for software devs)

服务方法应该只接受一个参数,它将是一个数组吗?

Should a service method only accept one argument, which would be an array?

这取决于方法的作用.假设您的示例处理表单的结果集,那么是的,这可能会起作用.在其他情况下,这可能是一个糟糕的选择.

This is dependent on what the method does. Assuming your example of processing a form's resultset, then yes this will probably work. In some other case it might be a poor choice.

我可以在表单中添加另一个字段,而不必更新控制器,只需更新服务即可. [...]

I can add another field to my form and I won't have to update the controller, just the service. [ ... ]

如果不传递数组,则可以设置带有多个参数的函数. [...]

If I didn't pass an array, I could setup functions with multiple arguments. [ ... ]

是的,在我看来,您对于这两种情况的论点几乎都是正确的.

Yep, your argumentation for these two cases is pretty much spot on for this use-case in my opinion.

我可以传递一个对象,但这有意义吗?如果我要创建一个对象,它应该是它代表的对象(在这种情况下为用户),对吗?但是,控制器实例化用户对象是否有意义?难道这不是服务层的全部要点吗?

I could pass an object, but does that make sense? If I'm creating an object, it should the be the object it represents (the user in this case) right? But does it make sense that the controller instantiates the user object? Isn't that the whole point of the service layer in the first place?

这取决于.例如,如果您使用的框架可以将表单表示为对象(例如Zend Framework和 Zend_Form ),您可以考虑将表单对象直接传递给服务.

This depends. For example, if you were using a framework which lets you represent forms as objects (such as the Zend Framework and Zend_Form), you could consider passing the form object straight to the service.

也许有一个参数,它包含一些带有多个参数的方法(当只有一到三个时)和一些接受数组的方法(当有很多字段时).这似乎是一场噩梦,因为您总是必须引用该类才能知道特定方法的要求.

Maybe there is an argument for having some methods with multiple arguments (when there are just one to three) and some methods that accept an array (when there are lots of fields). This just seems like it could be a nightmare, as you would always have to reference the class to know what that particular method was asking for.

通常应基于该方法的名称,使参数至少可以猜测一半.在我从事的工作中,我们有一个模型,其中包含企业和产品,企业可以在其中赞助产品.在ProductService中,我们有一个名为sponsorProduct的方法,该方法将业务和产品作为参数.您几乎可以猜测这将花费这两个时间(如果您仍然熟悉代码库的话)

You should usually aim to make the parameters at least half-guessable based on the method's name. In something I work on, we have a model which has for example businesses and products, where a business can sponsor a product. In a ProductService, we have a method called sponsorProduct which takes a business and a product as parameters. You can pretty much guess it would take these two (if you were familiar with the codebase anyway)

IDE通常也会为您提供帮助-它们提供代码辅助,可显示参数函数的作用.这是我认为IDE在大型项目中非常有用的主要原因之一,在这些项目中,您始终无法记住某个函数确切需要什么参数.

IDE's generally help you with this too - they provide code-assist which displays what params functions take. This is one of the main reasons I think IDE's are very useful in larger projects where you can't always remember what exactly a certain function needs as parameters.

关于参数计数,我认为通常您应该尝试使用单独的参数.这样,任何人都可以通过仅查看函数的签名轻松地查看所需的参数,并可以轻松定义类型提示和默认值.

As for parameter count, I think usually you should try to have separate parameters. This allows anyone to easily see what parameters are required by just looking at the function's signature, and allows you to define typehints and default values quite easily.

但是有一点很重要,那就是您获得了太多参数.这可能是+5左右,具体取决于它是哪种方法.在这种情况下,您可以考虑使用数组或称为参数对象"的东西,该对象本质上是一个包含调用的所有参数的对象.有关参数对象的更多信息,请此处

However there is a point when you get so many parameters it's too much. This is maybe at +5 or so, depending a bit on what sort of method it is. In this case you can consider using an array, or something called a Parameter Object, which is essentially an object that contains all the parameters for the call. More on parameter objects here

这篇关于用PHP设计服务层类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆