Re: Re: [Pre-RFC] Scalar object methods (with a working implementation)

From: Date: Sun, 05 Jul 2026 01:43:47 +0000
Subject: Re: Re: [Pre-RFC] Scalar object methods (with a working implementation)
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-131773@lists.php.net to get a copy of this message
Hi Michal, > The receiver in your example is $x, an untyped local, so $x->length() > doesn't dispatch at all. Fine, then take the corrected version. Every narrowing you apply to keep dispatch "locally provable" makes the feature worse, because the property that matters to a user is the one being trimmed away: if <expr> is a string, <expr>->trim() should work. Not "works if you assigned it to a typed local first," not "works unless it came from a bare function call," not "works depending on what's above or below it in the file." Seeing $s->trim() where $s is a string, I should know it works. A construct where identical AST dispatches or doesn't depending on file position, a redundant cast, or whether a declaration sits above or below the call is not something people can reason about. > restrict that form to internal functions, where the compiler and the > analyser agree unconditionally This is more fragile than the problem it fixes. A static analyser often can't tell whether a function is "internal." A function added as a builtin in 9.1 but provided by a polyfill on 9.0: a project supporting both has no single answer. The same call is internal on one target and userland on the other, so the analyser can't soundly decide whether it dispatches. That's a language construct whose validity depends on the runtime present. Also, this does not take into consideration unresolved names at compile time, calling strlen($s)->multiply($y) inside namespace App with no imports. How would this be handled? Would it also not work? > The definitions aren't hidden. They're ordinary .stub.php files in core > (str.stub.php, ...), which is what PhpStorm, PHPStan and Psalm already > consume. This isn't accurate, and I maintain Mago, so I can speak to it directly. We don't consume PHP's .stub.php files. Neither do PHPStan or Psalm; they ship their own stub sets, because core's stubs aren't expressive enough for analysis: no conditional return types, no generics, no ranges. Publishing str.stub.php doesn't give analysers what they need. PHPStan: https://github.com/phpstan/php-8-stubs/tree/main/stubs Psalm: https://github.com/vimeo/psalm/tree/6.x/stubs Mago: https://github.com/carthage-software/mago/tree/main/crates/prelude/assets/extensions > an analyser has to special-case scalar dispatch regardless, since a > string isn't an object It doesn't. If $s->trim() works whenever $s is a string, the analysis is clean: I resolve string methods against whatever interface defines them, as if $s were an instance of it. What forces a hack is your design, a construct valid or invalid for identical AST depending on file order and surrounding declarations. I don't know how I'd model that soundly. Your approach creates the special-casing you say is unavoidable. > That last one is taste The "should scalars have methods" part is taste. But this already existed, unrestricted, and worked: Nikita's scalar_objects ( https://github.com/nikic/scalar_objects) dispatches on the runtime type, so $str->length() works for any string, regardless of where it came from. > so I won't try to talk you out of a no. You don't have to :P I don't vote. Cheers, Seifeddine

« previous php.internals (#131773) next »