Skip to content

Adding object type-hint and return-type #2080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from

Conversation

brzuchal
Copy link
Contributor

This patch is for PHP RFC: Object typehint.
This patch enable and adjust the code, add phpt.

@HallofFamer
Copy link

HallofFamer commented Aug 13, 2016

I say no to this, dont like adding object to reserved name. I use Object as root class for all my classes, it breaks my application completely. I think object can be used as parameter type hint already, or you can just use StdClass as typehint, so this is totally unnecessary either.

@KalleZ
Copy link
Member

KalleZ commented Aug 13, 2016

@HallofFamer, you should use the mailing lists once this RFC reaches discussion stage instead of here

@brzuchal
Copy link
Contributor Author

@HallofFamer Root class was discussed with this feature but was put away for another discussion. It'll be discussed with another RFC after this one. For now it'wasn't discussed yet at internals mailing lists so far.

@adragus-inviqa
Copy link

So... how does type-hinting it to stdObject make it catch custom objects? Moreover, how's breaking your application an argument against this RFC? Since yours is a high-level class, it wouldn't that hard to refactor it, right? Other arguments should be brought up, not our specific issues.

@brzuchal
Copy link
Contributor Author

@HallofFamer having a root class which for eg acts exactly as \stdClass is agood idea which I have proposed also but it needs additional discussion. Having \Object class implementation in root namespace isn't a good practice. Having any non-namespaced class implementation can lead to problems with language deprecation. object type-hint and return-type is needed there where you expect object no matter oh it's class. That is needed in object wrappers, ORM's where entity expected and there where core implementation fallbacks into \stdClass for eg. PDO statement fetchObject method - without it you cannot type-hint either declare return-type. Maybe root class \Object from \stdClass together in one RFC could be discussed later. Did it help you to understand tge need fir this feature?

@HallofFamer
Copy link

HallofFamer commented Aug 14, 2016

@brzuchal
My Object class is not in the root, but inside a nested namespace of course. And nope I dont think there is a need for this feature. Object is very generic, returning an object is not very useful unless the specific type of object is known. You dont know what properties and methods this object has, it is not polymorphic nor reliable. Of course, if there is a root object class with some default methods applied to every object class(such a Object class in Java and C#), then type hinting on object type will be more useful, as you know you can safely call these methods.

In PHP though, objects lack a root class and has no properties/methods by default. To me, a method that accepts/returns object type doesnt tell me exactly what it is accepting/returning, I use an interface or abstract class type for hinting if I want to use type hinting feature. In your example of ORM, just dont specify return type, it is optional anyway. Like I said before, you use type hinting when the type is specific, rather than a generic object. Same reason why there is no need for typehinting on resource, because without knowing its specific type of object or resource its not useful at all.

So yeah, my point stands that, unless a root object class is introduced with some methods(such as gethashCode(), which can be just like spl_object_hash()) that can be used on every object, having object type hinting is unnecessary.

@brzuchal
Copy link
Contributor Author

@HallofFamer you're missing the point of object type-hint and return-type it is usefull when you cannot expect any specific object class, you just don't need to inspect variable with is_object. Such internal validation exists in many places in libraries like ORM and any object wrappers implementation, especially in unit tests: phpunit, phpspec, behat any other libraries which cannot pin type hint to any specific implementation. Object is very generic - yes of cource that's why such type-hint and return-type is usefull, missing root class in PHP lang couse this need. Type hint is created for type safety, right now you cannot expect it from PHP lang in case of objects. In may places there are some fallbacks to \stdClass so this is also not a root class, but simply in some internal functions like json_decode there are in result \stdClass instances, in fetchObject in PDO there is optional class, but in case of loading error it fallbacks into \stdClass so you cannot extect from simple entity it's class and you canno type hint. You need dynamically check with is_object insidde method/function if it is an object. Another porblem is missing such type-hint and return-type you have to leave dynamic declaration, so there is possible missusage at inheritance, because of missing it in higher class impl.

@HallofFamer
Copy link

HallofFamer commented Aug 14, 2016

@brzuchal
I am not missing the point. As I said before, object type hinting is useless if all you can get is that it is an object, without any information such as which class it inherits with, which interface it implements or which methods are available. There is a reason why you dont type hint on resource, because the variable being a resource doesnt tell you anything. You dont know whether it is a curl resource, a mysql resource, a file resource or whatever. Same story here with object type hinting, and I dont see why it is a problem using is_object check anyway.

In those edge cases as you mentioned, just dont use type hinting at all, if there is no benefit of type hinting, really. In your defense, it may be a better idea to introduce a root class, but before a root class is implemented I dont see type hinting with object is useful. I am against reserving object as keyword also, because it just breaks backward compatibility with something totally unnecessary, especially when it is already PHP 7.1 and 7.2.

@brzuchal
Copy link
Contributor Author

@HallofFamer object type hint doesn't have to bring information about class - such functionality already exists in PHP so what is your problem? In case of resources maybe yes this type-hint is not used at all but those may be changed in feature versions of PHP into object one resource-less. There are many people thinking that type-hint and return-type is usefull. You're sticked into useless because it couse problem in your code and I think that's all. RFC is going to be implemented and described the voting will say it's usefull or not.

@nikic nikic added the RFC label Aug 15, 2016
@HallofFamer
Copy link

@brzuchal
Well it is useless typehinting, just like resource and mixed if implemented, since I've pointed it out again and again that type hinting on something as generic as object type is useless. Yes you are right that the functionality of bringing information about class already exists, then whats the need for type hinting object then? Of course many people think type hinting is useful, but object type hinting is not useful. See the difference? The fact that it causes problem in my code isnt an issue, I refactored my code from time to time. The problem is, it breaks things for no gain. If I use namespace or trait as class name, I refactor, because PHP introduces a good feature and there is huge benefit for this. However, object type hinting is not, it is just as I said, useless.

@jerrygrey
Copy link

@HallofFamer I hate to break this to you but the world doesn't revolve around you, there are many benefits to this change as pointed out in the rfc, the automatic type validation is an interest of mine. Ongoing refactoring is an improve part of a programmer's job and I don't think it is asking much to do a simple rename, I did it, went from object to stored_object. I also would point out that object is already a soft reserved word in PHP7 and its use is discouraged.

@sirsnyder
Copy link

There is no need to break existing code. This stuff can be done in userland. To type hint against Object, create an interface Object an implement it to all your classes.

@HallofFamer
Copy link

HallofFamer commented Aug 15, 2016

@jerrygrey
The world does not revolve around you either, there are not enough benefits to justify this RFC. And refactoring isnt a problem, I always refactor my code, but this refactor will be completely nonsense since it fits an OO programmer's mental model that the root class for every other class is called Object. Changing from object to stored_object is not just more typing, but also logically absurd.

Maybe PHP can make StdClass the root class for all classes, thus solving this problem completely. But this will require another RFC, and I am not sure how likely it will be done. Or just as @sirsnyder said, create a root class or interface that all your classes inherit, like I did with Object class, and problem solved. Also soft reserved keyword doesnt mean anything, its not reserved after all.

@Majkl578
Copy link
Contributor

Generic object typehint could be useful in many ways, look e.g. at Doctrine ORM, a lot of public OO API deals with arbitrary/generic objects. Another example are serialization libraries like jms/serializer. The primary benefit of this typehint is in libraries imho.

Also note that objecŧ is a reserved keyword since PHP 7.0 so this is not really a BC break, it's just your code that is fragile.

This stuff can be done in userland.

Not really across multiple libraries / code bases. Maybe PSR could be a way, but support on language level is much better way.

Maybe PHP can make StdClass the root class for all classes

That doesn't make much sense. stdClass is meant to be used as an object to store arbitrary data, pretty much like object variant of the array.

@HallofFamer
Copy link

HallofFamer commented Aug 16, 2016

Nope it is not useful in any ways, except that it tells you that it is an object of unknown class, which cannot even be used to enforce polymorphism. You are better off just not to use type hinting at all, if type hinting doesnt really tell you anything useful. The better way is to define an object root class that every PHP class implicitly extends to, the stdclass recommendation is just one of the several variants I can think of, which is not meant to be the ideal solution anyway.

Object is the root class for essentially every programming languages that support OOP, with some exceptions such as ObjectiveC. It fits the mental model of a programmer that the root class is named Object, reserving the keyword object makes it impossible for userland implementation of Object root class. I've mentioned before, refactoring isnt a problem, but refactoring that is completely unnecessary and reduces productivity isnt the kind of refactoring we need.

Of course, there are other ways to solve the problem, such as making PHP keyword case-sensitive, but it will result in too much BC break that is pretty much impossible now for this programming language. Alternatively, object type hinting will not cause 'object' to be reserved, instead the word 'object' resolves to Object class if defined, or object type if undefined. There are many ways to achieve this, BC break for the sake of BC break, doesnt sound like a good idea to me.

@brzuchal
Copy link
Contributor Author

I've prepared also version with root-class for POC and some tests and actually it slows down about 5% at object instantation if all clases inherits from \Object so actually if both features doesn't give anything extra than type-hint and return-type features with all those benefits from RFC I prefer type safety and performance. PHP hasn't be Java that is why PHP is dynamic language and has quite good performance.

@brzuchal
Copy link
Contributor Author

@sirsnyder actually your are unable to do that in userland! You can implement \Object interface and implement your objects, but such implementation won't work with libraries and you still cannot expect objects of \stdClass! Anyway object is soft-reserved word and you should not use it in you class names! Read the docs http://php.net/manual/en/reserved.other-reserved-words.php

@HallofFamer
Copy link

HallofFamer commented Aug 16, 2016

Well slowing down by 5% is negligible, from statistical point of view it may not even be valid, and no one is going to make a deal for performance unless its at least 10%-15% slowdown. Ideally the root object class isnt just an empty object sitting there for type hinting purpose, it should have some useful methods such as hashCode(), getClass(). And that's exactly why it is more useful than your object type hinting, because now at the very least, you can be sure that every object has some methods you can call. For your object type hinting, it only tells the variable is an object. Nothing more, nothing less, and nothing really helpful.

And what does Java have anything to do in this discussion? Having a root Object class is not making PHP look like Java, it makes PHP a more complete OO language. Almost every OO language has Object as root class name, even javascript. PHP is like jack of all trades, it brings in whatever is useful, from any existing programming languages. PHP's base OO model looks like Java's, namespaces looks like C++/C#'s, closures looks like javascript's, trait looks like scala's, generator looks like python/ruby's. See the point? Also soft-reserved keyword doesnt mean anything, it is not reserved and I can use it anyway.

@brzuchal
Copy link
Contributor Author

@HallofFamer sure I see the point you can post it into php-internals mailing list, this RFC deosn't fit your needs and that's all. World doesnt revolve around you and your broken implementation and I'm not goint to convince you anymore.

@HallofFamer
Copy link

The world doesnt revolve around you either, it revolves around nobody, which is why you are making this RFC and I am arguing against it. You have you rights to make it, I have my rights to go against it. I am not trying to convince you either, since apparently you cannot be convinced and are determined to make breaking changes for little benefit.

@Majkl578
Copy link
Contributor

It seems to be segfaulting on Travis: https://travis-ci.org/php/php-src/jobs/170057961#L536

@RyanNerd
Copy link

A wonderful addition for DI especially, and for those (such as myself) who prefer to use objects as their propertyname->value pair lists instead of arrays.

@@ -925,6 +928,8 @@ static zend_always_inline zend_bool zend_check_type(
}
}
return 0;
// } else if (arg_info->type_hint == IS_OBJECT) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left overs ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, it's okay now.

@raziel057
Copy link
Contributor

@brzuchal Is variance in typehint working for all kind of object inheritance or just with "object" keyword ? Maybe it's out of the scope of this PR but I think it's important to keep in mind it for consistency.

<?php
class Animal {
    public function test() : Animal {}
}

class Dog extends Animal {
    public function getClone() : Dog {
        return clone $this;
    }
}

$dog = new Dog();
$dog->getClone();

@brzuchal
Copy link
Contributor Author

@raziel057 It only works for object keyword - this behaviour is described as covariance and is AFAIK not possible to achieve for all types at this moment.

@raziel057
Copy link
Contributor

@brzuchal Ok thanks for your quick answer and for your hard work!

@Majkl578
Copy link
Contributor

Hi @brzuchal, do you plan to go forward with this and move it to the voting phase so it could eventually make it to PHP 7.2?

@Ocramius
Copy link
Contributor

Agree: very needed addition 👍

@brzuchal
Copy link
Contributor Author

brzuchal commented Jun 4, 2017

I've changed my remote branch to version before variance patch. But I don't know how to trigger builds on this PR. Can someone help please?

@nikic
Copy link
Member

nikic commented Jun 4, 2017

@brzuchal You need to rebase the PR to current master. The CI build needs to be able to merge into master without conflicts.

@brzuchal
Copy link
Contributor Author

brzuchal commented Jun 7, 2017

@nikic I think I did it. My changes are passing AppVeyor and Travis with ZTS and debug enabled, don't know why build without ZTS and debug has failed, but I can assume this is because of unrelated changes - because all object type tests passed. I also removed tests which were checking argument type inheritance because of Parameter type widening which was accepted and implemented already in 7.2.

@brzuchal
Copy link
Contributor Author

brzuchal commented Jun 8, 2017

@sgolemon could you please review and merge?

}

--EXPECTF--
Fatal error: Interface function One::a() cannot contain body in %s on line 4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not what you want to test here ;)

Stack trace:
#0 %s(12): class@anonymous->a()
#1 {main}
thrown in %s on line 9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks redundant with Zend/tests/object_types/return_type_in_class.phpt, which also has an object type on the interface.

@nikic
Copy link
Member

nikic commented Jun 12, 2017

Can you please add a test for object $foo = 42? I think the error message will be misleading.

@nikic
Copy link
Member

nikic commented Jun 25, 2017

Merged as 8e10c9d with the remaining issues fixed. Thanks!

@nikic nikic closed this Jun 25, 2017
@brzuchal
Copy link
Contributor Author

@nikic Thank you very much. I hadn't enough time to fix issues.

@pinepain
Copy link
Contributor

pinepain commented Jun 26, 2017

@brzuchal, @nikic and all contributors & reviewers: thank you for making this possible, for your time and efforts!

@Ocramius
Copy link
Contributor

Ocramius commented Jun 26, 2017 via email

jrfnl added a commit to PHPCompatibility/PHPCompatibility that referenced this pull request Aug 2, 2017
`object` was already a soft reserved keyword as of PHP 7.0.

As of PHP 7.2, it:
* can be used as a parameter type hint
* can be used as a return type hint
* has become a "hard" reserved keyword.

References:
* https://wiki.php.net/rfc/object-typehint
* php/php-src#2080
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.