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

Better support for internal PHP classes default parameters #162

Open
Ocramius opened this issue Apr 14, 2014 · 28 comments
Open

Better support for internal PHP classes default parameters #162

Ocramius opened this issue Apr 14, 2014 · 28 comments

Comments

@Ocramius
Copy link
Owner

As @guilhermeblanco suggested, we can fully support internal PHP classes methods' default parameter values by using a trick like following.

Assuming this is an internal php class, and that we cannot discover the default value for $foo via reflection:

class SomeInternalClass
{
    public function doStuff($foo = 'bar') {}
}

This code should become like following in the proxy:

class MyProxy extends SomeInternalClass
{
    public function doStuff($foo = ProxyManager::PLACEHOLDER)
    {
        if (ProxyManager::PLACEHOLDER === $foo) {
            parent::doStuff(); // ignore parameter, use defaults
        } else {
            parent::doStuff($foo);
        }
    }
}

That will allow us to fully support default values in proxies for internal PHP classes.

Please note that this does not apply to class-hinted parameters, as the default value for a class-hinted parameter can only be null

@Ocramius Ocramius added this to the 1.0.0 milestone Apr 14, 2014
@Ocramius
Copy link
Owner Author

Ping @mnapoli you were interested in this.

@mnapoli
Copy link

mnapoli commented Apr 15, 2014

Thanks. What is the value of ProxyManager::PLACEHOLDER? Don't you risk some conflicts if you set it to an arbitrary value?

@staabm
Copy link
Contributor

staabm commented Apr 15, 2014

In Java you would use something like PLACEHOLDER = new Object() and do a strict comparison, to make it only match itself.

@mnapoli
Copy link

mnapoli commented Apr 15, 2014

OK if it's a specific object instance then that's fine, I was afraid it was going to be something like null, or something more creative to avoid collision in most cases like NaN or PI or infinity :p

@mnapoli
Copy link

mnapoli commented Apr 15, 2014

(using Nan or PI or infinity would be stupid right… it's not like anyone did it at some point in their life right… at least I didn't… I mean, maybe I just thought about using it… it was just one time… :p)

@lisachenko
Copy link

@mnapoli +1, I also thought about NaN ) but it was just one time too )) I like very much this crazy check:

$value = ...
if ($value !== $value) { // happy debug
    echo "It's crazy NaN value";
}

@Ocramius
Copy link
Owner Author

@staabm sadly no java :(

@mnapoli we can randomize/generate the value to ensure that it is always unique

@mnapoli
Copy link

mnapoli commented Apr 15, 2014

@mnapoli we can randomize/generate the value to ensure that it is always unique

Risky :p

@staabm
Copy link
Contributor

staabm commented Apr 15, 2014

how about a float with a lot of number behind the comma, so it gets very unlikely it can match any existing real world numbers..?

@Ocramius
Copy link
Owner Author

It will just be a string ;-)

@Ocramius
Copy link
Owner Author

Ocramius commented Oct 5, 2014

Deferred to 2.0.0: too much of an edge case, and = null is pretty much always the default.

@Ocramius Ocramius modified the milestones: 2.0.0, 1.0.0 Oct 5, 2014
@Ocramius Ocramius removed this from the 2.0.0 milestone Dec 30, 2015
@Ocramius
Copy link
Owner Author

Removed from 2.0.0 milestone: while this can be implemented, I'd rather have something like https://github.com/Roave/BetterReflection deal with this sort of problem instead.

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

So please, take it more seriously and at least put a disclaimer.

Sorry, but unless you have practical advice on how to resolve the issue, this is not constructive feedback.

Patches welcome, but I can't do much about internal symbols reflection being incomplete, because that's just how the engine behaves for types not defined in userland.

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

For your specific Redis issues, check the related issues here:

Specifically, from that last issue:

Btw, this is neither a bug in ProxyManager nor in this bundle: you will need to either fix this in the extension, or provide a userland shim that can be reflected.

@alekitto
Copy link

alekitto commented Dec 2, 2021

Trying to be constructive through a proposal: what about loading class definitions for these edge-cases from a stub file? Could it be viable?

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

Putting a disclaimer that library have edge-cases in README is a constructive feedback

Please re-read your comment, then, and perhaps ask someone to analyze it for you, so you can understand why it is not an acceptable human interaction:

  • with strangers you don't know personally
  • that provide you with a free service
  • that put lots of effort in it
  • that operate very seriously, with a long and regular track record
  • that, even after your inconstructive feedback, took the time to provide you with a set of references to similar problems, including potential workarounds

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

Trying to be constructive through a proposal: what about loading class definitions for these edge-cases from a stub file? Could it be viable?

@alekitto yes, see:

Beware that any mis-alignment between stubs and actual runtime symbols can still lead to problems.

Using something like BetterReflection is viable, but requires major rework of internals.

@azjezz
Copy link

azjezz commented Dec 2, 2021

@mnapoli we can randomize/generate the value to ensure that it is always unique

I think the best approach would be to use a combination of time, current directory/filename, and a pseudo random id.

$placeholder = uniqid(true, '__proxy_manager') . time() . hash('md5', __FILE__);

md5 because performance

@nicolas-grekas
Copy link
Contributor

nicolas-grekas commented Dec 2, 2021

There's only one sensible way fix to the issue with Redis or similar: send a patch to https://github.com/phpredis/phpredis/ It's an actively maintained lib. Asking OSS authors to write and maintain piles of code that are just workarounds is a waste of their time. Even if one doesn't know C, one can patch the definitions in the source code by using copy/paste and imitation. Please consider sending them a PR @ilya-levin-lokalise!

As far as this issue is concerned, what about closing it @Ocramius, for the reason I just gave? The PHP engine is getting stricter and stricter regarding type declarations, it's not like extension authors have any excuses.

@cmb69
Copy link

cmb69 commented Dec 2, 2021

It seems that issue has already been resolved. Proper reflection should be available as of 5.3.5RC1 in combination with PHP 8.

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

As far as this issue is concerned, what about closing it @Ocramius, for the reason I just gave? The PHP engine is getting stricter and stricter regarding type declarations, it's not like extension authors have any excuses.

Depends on whether this can still occur in the engine at all 🤔

@nicolas-grekas
Copy link
Contributor

Depends on whether this can still occur in the engine at all thinking

I think yes, having reflection out of sync from actual declaration is still possible, but it's now way easier to have them in sync AFAIK.
Maybe @nikic has some more info on the topic?

@cmb69
Copy link

cmb69 commented Dec 2, 2021

Depends on whether this can still occur in the engine at all 🤔

Yes, it still can happen. In some cases, a default cannot be specified (in this case because the parameter has no default; in other cases because the function may be overloaded like array_keys), and of course in some cases, because an extension has not yet been updated. Wrt. to the core and bundled extensions, there are only "few" such cases.

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 2, 2021

Yeah, problem is potentially still with ext-* stuff, including proprietary software. For proprietary stuff, there is a hard stop in such cases, because there would be no stubs either.

@nicolas-grekas
Copy link
Contributor

Idea (likely a bad one): use a variadic argument in place of this UNKNOWN default?

@azjezz
Copy link

azjezz commented Dec 3, 2021

actually that's a pretty good one, using

function foo($a = null, /* signature becomes broken here, use variadic argument */ ...$rest)

for

function foo($a = null, $b = UNKNOWN, $c = null)

could work, people get auto-completion based on the original class, so the signature of the proxy doesn't matter.

https://3v4l.org/u0V0a

@Ocramius
Copy link
Owner Author

Ocramius commented Dec 4, 2021

Overall potentially feasible, need to build some trickery for point-cut proxies, where the parameters are passed to interceptor callables (and keys may be missing), but it is likely feasible 🤔

@nicolas-grekas
Copy link
Contributor

Another idea: set null as default value and forward the call with parent::doStuff(...func_get_args()).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants