在 PHP 中重写子类中的函数时更改返回类型?
这很糟糕吗?或者说这在PHP框架中很常见?
例如,在父类中,有一个 save() 函数,它返回数据库中受影响的行数。然后在子类中,我重写此函数来执行一些预验证,并且还想简单地返回成功/失败的布尔值。
Is this bad? Or this is very common in PHP framework?
For example, in the parent class, there is a save() function which returns the number of rows affected in the database. Then in the child class, I override this function to do some pre-validation, and also would like to simply return a success/failed boolean value.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我同意这样的共识:改变返回值的类型(甚至含义)是不好的。
怎样
下面是它的糟糕情况的说明:假设您有一个接受字符串和“Writer”的函数:
这是原始的“Writer”类:
如果我们将“LazyWriter”传递给该函数
会 :假设
Writer::write()
的返回值是printThroughWriter
中的字符数已经被破坏,从而导致不一致。I agree with consensus that it's bad to change the type (or even the meaning) of the return value.
Here is an illustration how it will be bad:
Let say you have a function that accepts a string and a 'Writer':
And here is the original 'Writer' class:
What if we pass a 'LazyWriter' instead to the function:
The assumption that the return value of the
Writer::write()
is the number of characters inprintThroughWriter
has been broken, thus causing inconsistency.您应该覆盖底层代码,而不是合约。
所以,不,改变返回值(这是合同的一部分)是不好的。
You should be overriding the underlying code, not the contract.
So, no, it's not good to change the return values (which is part of the contract).
继承的思想是允许客户端可互换地使用类的子类型。如果您正在更改子类型的返回类型,那么您就会破坏继承的规范实用性,并且最终只会造成混乱:
“这里我采用了一种 Collection 类型,但是 myCollection.add() 是否会返回一个布尔值或添加的元素或其他内容?我不知道!我不能再用这种类型做任何事情了!我”我必须为每个子类型制定一个方法才能解决这个问题!”
The idea of inheritance is to allow clients to use the sub types of a class interchangeably. If you are changing return types of sub types then you are destroying the normative utility of inheritance and will just end up creating confusion:
"Here I take a type of Collection, but is myCollection.add() going to return me a boolean or the element that was added or something else? I have no idea! I can't do anything anymore with this type! I'm going to have to make a method for each sub type in order to handle this problem!"
是的,这很糟糕。该方法的客户很难知道这一点。除非,该方法旨在处理它(在本例中,它似乎并非如此)。
我会强烈建议反对。
Yes it is bad. It will be hard for the client of that method to be know that to expect. UNLESS, the method is designed to handle it (which in this case, it does not seems like).
I will strongly advice against it.
虽然 PHP 中没有强制返回类型,但与重写方法保持一致是一个好主意,因为否则意味着会增加耦合并减少封装。
从插座和设备的角度考虑公共方法及其返回类型。任何电器都应该能够插入任何插座,并且每个插座应该向每个电器输出相同量的能量,除非插座是专门为特定类型的电器设计的。如果有人决定绿色插座应该输出一种能量,红色插座应该输出另一种能量,会发生什么。突然之间,您必须始终关注您的设备正在处理的特定类型的插座。
设计公共方法和属性是完全相同的,并且重写的方法和属性应该始终表现一致,无论访问它们的上下文如何。
While there is nothing enforcing return types in PHP, it is a good idea to remain consistent with overridden methods because to do otherwise means that you will increase coupling and decrease encapsulation.
Think of public methods and their return types in terms of outlets and appliances. Any appliance should be able to plug into any outlet and every outlet should output the same amount of energy to each appliance, unless of course the outlet has been specifically designed for a specific type of appliance. What would happen if someone decided that green outlets should output one amount of energy and red ones another. Suddenly you'd have to always be concerned with the specific class of outlet that your appliance is dealing with.
Designing public methods and properties is exactly the same and overridden methods and properties should always behave consistently regardless of the context in which they are accessed.
我同意,这通常是一个坏主意。
如果您迫切需要从函数中传递除返回值之外的另一个值,则可以添加按引用传递参数。或者,如果出现错误消息,请使用异常。
I agree, that this is generally a bad idea.
If you desperately need to pass another value out of the function, other than it's return value, you can add a pass-by-reference parameter. Or, in case of error messages, use Exceptions.
您可以返回更指定的类型,例如来自重写方法的返回类型的后代的实例,而无需违反约定。
如果被重写的方法返回布尔值,则如果
0
返回值符合导致被重写的方法返回FALSE
且非零值对应于TRUE
返回值。如果有人在返回值上使用相同的比较运算符 (===
),这仍然可能会导致问题,但您通常仅在(例如)方法可能同时返回FALSE< 时才会看到这种情况。不同条件下的 /code> 和
0
。在您的示例中,重写返回类型并不比重写返回类型更具体,因此您不应该这样做。
You can return a more specified type, such as an instance of a descendant of the return type from the overridden method, without breaking a contract.
If the overridden method returned a boolean, the overriding method could instead return a number if
0
return value corresponded to the conditions that would cause the overridden method to returnFALSE
and non-zero values corresponded to aTRUE
return value. This could still potentially cause problems if someone used the identical comparison operator (===
) on the return value, but you typically only see this when (e.g.) a method might return bothFALSE
and0
under different conditions.In your example, the overriding return type is not more specific than the overridden return type, so you shouldn't do it.
我最终来到这里寻找正确的做法。
就我而言,我谈论的是一个测试类:
这就是我解决的方法:
我真的很喜欢这个解决方案,因为通过按住 Ctrl 键并单击 phpStorm,我可以找到原始方法。
在其他情况下,我可能不会更改返回类型,正如其他人所解释的那样,但 see 标签可以以类似的方式使用。
希望有帮助!继续摇摆;)
I've ended up here looking for a correct way of doing.
In my case I'm speaking about a Test Class:
That's how I've solved:
I really like this solution, because by Ctrl clicking with phpStorm, I'm leaded to the original method.
In other cases probably I wouldn't change the return type, as explained by others, but the see tag can be used in a similar way.
Hope it helps! Keep on rocking ;)