Skip to content
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

Added get_debug_type as new function #5143

Closed
wants to merge 9 commits into from

Conversation

markrandall
Copy link

@markrandall markrandall commented Feb 2, 2020

Alternative to #5142 exposing a new function get_debug_type which will return the class name if the type is an object.

RFC: https://wiki.php.net/rfc/get_debug_type

@markrandall
Copy link
Author

Will be changing the scalar types to represent their in-code versions.

@KalleZ
Copy link
Member

KalleZ commented Feb 2, 2020

This looks to be just as easily implemented in userland code, what is the rationale for implementing this in the core (the other PR didn't really give me any clue)?

The issue mentioned in regards to resources is notable, unless it returned something like: resource(xxx) (with xxx being the result of get_resource_type()).

@markrandall
Copy link
Author

This looks to be just as easily implemented in userland code, what is the rationale for implementing this in the core (the other PR didn't really give me any clue)?

Just a request from Beberlei that cropped up in a discussion with Derick. I've had to implement this pattern a few times in the past week, and Beberlei mentioned it appears almost 200 times in Symfony and almost 400 times in Magento.

Perhaps more significantly, it's an opportunity to change the return values on this to match what is expected from type hints e.g. int not integer, float not double. It might make more sense for just hitting up zend_get_type_by_const for everything other than IS_OBJECT.

@nikic
Copy link
Member

nikic commented Feb 3, 2020

@KalleZ Basically this is the function you need to generate the expected XXX, YYY given style messages that PHP uses without adding a bunch of boilerplate for every exception you throw.

@KalleZ
Copy link
Member

KalleZ commented Feb 3, 2020

@nikic that makes sense to me, +1.

Side question, do we want to distinguish resource types or just flat out return them as "resource"? Given resource is a valid class name, then identifying the resource type could potentially solve that collision.

@kocsismate
Copy link
Member

kocsismate commented Feb 4, 2020

@KalleZ I was basically wondering on the same thing in the other PR.

So I'm curious if it would be worth to reserve the resource class name from use? Or is there any reason I am not aware of why it's the only type that is a valid class name in the same time (ok, along with double array - but at least the parser fails in that case)?

EDIT: I understood it in the meanwhile: as resource is not a real type (it's just a "confusable" type :) ), there is no reason not to support a class with this name as it is going to work as a type declaration.

@KalleZ
Copy link
Member

KalleZ commented Feb 4, 2020

@kocsismate thinking about it, I think it might be better to just leave the issue open but instead invest time in looking at changing resources into opaque objects (similar to how ext/gmp and ext/gd does) over the course of the 8.x series and then the issues fixes itself and we don't reserve a keyword while allowing for a more powerful typing with functionality implemented in the core.

@nikic nikic added the RFC label Feb 5, 2020
@nikic
Copy link
Member

nikic commented Feb 5, 2020

Implementation looks fine. This is going to need a (small) RFC though. Expect some bikeshedding on names...

@nicolas-grekas
Copy link
Contributor

Thank you for opening this PR, we really miss this helper IMHO!
What about improving the display name for anonymous classes?

the polyfilling code could be like that (inspired from what we do in Symfony):

function get_debug_type($value): string
{
    if (!is_object($value)) {
        return gettype($value);
    }

    $class = get_class($value);

    if (0 !== strpos($class, "class@anonymous\0")) {
        return $class;
    }

    return (get_parent_class($class) ?: key(class_implements($class))).'@anonymous';
}

@nikic
Copy link
Member

nikic commented Feb 5, 2020

Cutting class@anonmyous off at the \0 makes sense to me, as we do that for error messages as well.

Regarding use of the parent class / implemented interface, I'd only do that if we actually change the class name to look like that.

@nicolas-grekas
Copy link
Contributor

nicolas-grekas commented Feb 5, 2020

Cutting class@anonmyous off at the \0 makes sense to me, as we do that for error messages as well.

ONLY if using the parent/interface as proposed! otherwise, we'll be unable to implement using them in userland with this function (and this would void the benefit of introducing it)

Regarding use of the parent class / implemented interface, I'd only do that if we actually change the class name to look like that.

That could be nice, but it could have BC consequences (breaking the code above)...

@nikic
Copy link
Member

nikic commented Feb 5, 2020

ONLY if using the parent/interface as proposed! otherwise, we'll be unable to implement using them in userland with this function (at this will void the benefit of introducing it)

Why? Your code should still work just fine as long as you drop the match on the \0 at the end.

@nicolas-grekas
Copy link
Contributor

get_debug_type($anonymousClass) should NOT return class@anonymous. If it were, we wouldn't be able to provide the improvement we do with parent/interface from the output of the function. But I think I didn't get what you meant :)

@nikic
Copy link
Member

nikic commented Feb 5, 2020

function get_extended_debug_type($value) {
    $type = get_debug_type($value);
    if ($type === 'class@anonymous') {
        $class = get_class($value);
        return (get_parent_class($class) ?: key(class_implements($class))).'@anonymous';
    }
    return $type;
}

I don't think there's a lot of value in ^-- that though, it doesn't seems like important information.

Basically get_debug_type() should match the way PHP would display the value in an error message -- if that is going to be ParentClass@anonymous, that's fine. But if it's class@anonymous (as it is right now), then that's what the function should return.

@nicolas-grekas
Copy link
Contributor

nicolas-grekas commented Feb 5, 2020

Yes, it's true that we can implement get_extended_debug_type(), but we could also totally implement get_debug_type() right now. We didn't because that'd mean yet another package/dependency, with all the associated maintenance overhead. We'd better keep the current code, which is fine...

I don't think there's a lot of value in ^-- that though, it doesn't seems like important information.

Actually it's critical information: when using anonymous classes as exception classes, the default error message is totally useless as far as the class name is concerned. Same for anonymous objects found in stack traces. This is the reason why I tend to avoid using them in portable classes, and why I implemented this parent/interface display in the tools I'm using (Symfony Debug/ErrorHandler). Not everyone uses Symfony, so it would be awesome if PHP could borrow this.

@nicolas-grekas
Copy link
Contributor

Could it be worth adding the resource type?
get_debug_type($resource) => 'resource (stream)' ?

ext/standard/type.c Outdated Show resolved Hide resolved
ext/standard/type.c Outdated Show resolved Hide resolved
ext/standard/type.c Outdated Show resolved Hide resolved
Copy link
Contributor

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

Really nice!

RETURN_NEW_STR(zend_strpprintf(0, "resource (%s)", name));
} else {
RETURN_INTERNED_STR(ZSTR_KNOWN(ZEND_STR_CLOSED_RESOURCE));
}
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't it miss "IS_UNINITIALIZED" used with typed properties?

Copy link
Author

Choose a reason for hiding this comment

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

They throw upon trying to read them, so could not be used in an expression.

nicolas-grekas added a commit to symfony/polyfill that referenced this pull request Mar 3, 2020
This PR was merged into the 1.15-dev branch.

Discussion
----------

[Php80] Add get_debug_type()

Waiting for
- [ ] php/php-src#5143
- [ ] https://wiki.php.net/rfc/get_debug_type
- [x] php/php-src#5153

Commits
-------

61168ea [Php80] Add get_debug_type()
symfony-splitter pushed a commit to symfony/polyfill-php80 that referenced this pull request Mar 3, 2020
This PR was merged into the 1.15-dev branch.

Discussion
----------

[Php80] Add get_debug_type()

Waiting for
- [ ] php/php-src#5143
- [ ] https://wiki.php.net/rfc/get_debug_type
- [x] php/php-src#5153

Commits
-------

61168ea [Php80] Add get_debug_type()
Copy link
Member

@nikic nikic left a comment

Choose a reason for hiding this comment

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

Please add an UPGRADING note and squash when merging.

@nikic
Copy link
Member

nikic commented Apr 23, 2020

Rebased and merged as ef0e447.

@nikic nikic closed this Apr 23, 2020
@carusogabriel carusogabriel added this to the PHP 8.0 milestone May 29, 2020
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.

None yet

8 participants