The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Yes. ArrayAccess' behaviour is a subset of array. You can't subject it to the common array manipulation functions, for example.

Let's pretend that in this situation, the function only needs that particular subset behaviour. Otherwise, pretend that I want to pass an object implementing some of the other SPL interfaces, such as Iterator.

Well actually yes. In many cases the simplicity that comes with this kind of typing overcomes the flexibility of allowing developer to pass an object that implements ArrayAccess and/or Iterator and maybe even some other interfaces as well.

For example think about a framework that takes a config array as a parameter on some method. Then this array is passed from method to method and then some method uses function such as array_reverse. It would be a frustrating task to a developer to figure out why the code threw a warning (propably he would first guess this warning is some bug of the framework itself).

This becomes just stupid if I want EVERY method that takes an array as parameter to support objects that implement these special interfaces.

Yes, but only if your premise is that you want to enforce type. If you just take any argument, and use it as if it was an array - then you're fine. This of course relates very closely to your next quote :

I understand that your argument is that it fails earlier, and thus makes it easier to spot the problem. I won't judge which is more appropriate, but it's important to understand that both styles have pros and cons. Typehinting may help you fail early, but it also imposes some bureaucracy on the developer, and is less flexible.

This is the one of the problems with PHP's implementations of Interfaces; if you use a type hint, your method becomes locked into that one type of object. In Java, you don't have this problem since you can simply overload the method, making a version that accepts arrays, another that accepts iterators, etc.

And this is what I find a bit paradoxical about PHP's inclusion of interfaces; in Java they're a way of making your code more agile (and in fact the language would be useless without them), whereas in PHP they actually make your code less agile.

However, I'm pleased to discover that I still feel I'm using them properly. As I mentioned earlier, I'm the framework developer on a team of four. I author tightly controlled domain objects. I'm responsible for ensuring conformity to our framework's API.

If one of the other developers needs a feature or change or whatever, they have to come to me for it. So, for my job responsibilities, interfaces (proper) help me enforce the API.

And this is what I find a bit paradoxical about PHP's inclusion of interfaces; in Java they're a way of making your code more agile (and in fact the language would be useless without them), whereas in PHP they actually make your code less agile.

Quite obvious, but nevertheless something I hadn't considered before. Damn. I wonder why?

How does it makes the code less agile? For the code to work correctly you will still have to implement the methods that will eventually be called. Interfaces in PHP just makes this more verbose and explicit, hence the arguments that interfaces are good for documentation.

Personally, I don't use them. I think it just introduces unnecessary clutter, however I fail to see how they would make the code less agile.

The problem isn't interfaces themselves, but their use in conjunction with type hinting; they add rigidity to your code, making it less agile because changes in one place can lead to changes in other places. This increases the cost of change, and agile methedologies are all about decreasing that cost.

So a new method needs to be added to the passed-in object ... regardless of whether you are using an interface, you're still going to have to add that new method to the passed-in object. So where is the increase in cost? That you have to define a function in the interface as well as the class? Barely worth mentioning.

So changes in one place are going to lead to changes in another place regardless of interfaces. The only difference, which I stated earlier, is that with the verbosity of interfaces, we now have to define, at most, one more method signature.

Let's use an example: Your client wants you to model some animals, so you create an IAnimal interface. Your animals need to eat food, so you add an eat(Food $food) method to your interface, and then implement your different animals. One day your client decides he'd like to add some goats, and you realise that your goats don't just eat food, sometimes they eat garbage. So what do you do? You need to change your goats so that they simply eat($stuff), but that means changing your interface, which then means changing every single class that implements IAnimal. Based on your initial requirements, you made the assumption that your animals would only ever eat food; but the requirements changed, and your prediction turned out wrong, so now you have to adapt your code to the new requirements, something that is more complex than it could be because of the typehinting. Hence, type hinting (and static typing in general) increases the cost of changes, decreasing agility.

It's a contrived example; the fact is that there will always be cases where you will need to change the types of arguments your methods should accept, and by locking them in with typehints, you risk needing to make far-reaching changes later.

....lets say your code is designed so that it can only process food and not garbage. Typehinting an interface is in this case therefore specifies the minimum required contract (which without typehinting, you would probably have to check for in your code anyhow -- unless, perhaps, you rely only on test cases to ensure correctness). Changing requirements often DOES require changing and reviewing code in far reaching ways, not?

...which surely is an argument to minimise such changes as far as possible.

Personally I wouldn't use hints unles I was using a DependencyInjection tool which requires them. I can't think of a unit test which would produce a false positive for lack of hints. If it works, it works and hints don't change that. You could get false negatives signalling that the constraints need to be relaxed (ie dump the hints). I think it's best to try to strip away everything that's not absolutely essential since this makes refactoring easier.

....lets say your code is designed so that it can only process food and not garbage. Typehinting an interface is in this case therefore specifies the minimum required contract (which without typehinting, you would probably have to check for in your code anyhow -- unless, perhaps, you rely only on test cases to ensure correctness).

The trouble is that the "minimum required contract" may end up changing, and if you're using type hinting that change becomes more far reaching than it would be otherwise. Without the type hint, you can selectively make some of your animals consume things other than food without having to change anything about the rest of the animals.

Yes, of course; agile development is a recognition that change is inevitable, so it should be as easy as possible, and type safety is an impediment to that.

I've been with you all along until that last statement, which I feel is more general than it should be. All this time you guys have been discussing using type hints in PHP, which IMHO is a very small subset of what I'd call "type safety". I totally agree that using type hints in a language that is otherwise not anywhere near type-safe makes your code less agile. However, I do not agree that in general type safety results in less agility.

I really do not want to start a statically vs. dynamically typed debate (we've all been there before), but I do want to point out that the meta-information that types provide in a language like Java makes it possible for many common types of refactorings to be much simpler than they would be otherwise, due to the existence of tools that can analyze that information. Take something as simple as changing the name of a method. Often times you'll pick a name for your method, and after the design or your application is a little more fleshed out, you'll realize that the name is not as clear as it could be. Often you don't need to change the implementation at all, it's just that the name is inconsistent with other names, or is slightly confusing. Often when working with PHP I'll find myself debating over whether it's confusing enough to warrant having to manually update it across a dozen or more files. Yes, I'm more than aware that there are editors that will do search and replace, even using regex. However, it still takes time to make sure you're not replacing any false matches. Constrast this with Eclipse, where I select the method, hit ALT-SHIFT-R, type the new name, and hit enter. That's all that's required, and I can do it in less than 4 seconds.

That may not seem like a big deal, but every little bit adds up. And renaming methods is just the tip of the iceberg. Really, unless you've got experience with a modern refactoring IDE, you should consider whether there is something you're missing. I know, at least for me, that I'm far more merciless with my refactoring when there are tools to automate some of it for me than I am when I have to do it all by hand. If this could be achieved without static typing, I'd be all over it, but I haven't seen or heard of it yet (outside of the Smalltalk community, which I have on my list to check out at some point...)

Of course I'm sure many would argue that static typing imposes enough other limitations that it results in a net loss in agility, even with automated refactoring tools taken into account. That has not been my experience, but I accept that others may differ. Just wanted to present a different view on the matter...

I still don't see how typehinting impinges on the idea that changing requirements require changing code. If anything, it quickly points out where code will need to be changed. Whether you typehint or not, your methods will need to be aware if suddenly an incompatible (ie: an unexpected) object is passed-in. Typehinting merely states at the outset that a given piece of code has certain expectations. Personally, I don't subscribe to the view of absolute generality -- all concrete solutions have limitations; what is the problem in explicitly declaring them? If you need to refactor and modify code at some point to add more sophistication -- aren't tools (and hints or features at any rate) to flag where issues will arise beneficial in those cases? FWIW, I don't advocate typehinting everything in PHP -- just those cases where minimum conditions need be met unconditionally to prevent code breakage. ...or maybe this is my view because I write a lot of library type code and can't trust what people would do with it

I still don't see how typehinting impinges on the idea that changing requirements require changing code. If anything, it quickly points out where code will need to be changed. Whether you typehint or not, your methods will need to be aware if suddenly an incompatible (ie: an unexpected) object is passed-in.

Well, not really. You will get in error if an object of a different type than the programmer specified, is passed in - not if it's incompatible. There's a slight difference.