Hey Robert,
On Tue, 19 Mar 2024 at 17:24, Robert Landers <landers.rob...@gmail.com> wrote: > Hello internals, > > I've been thinking about this as an RFC for awhile, but with generics > being far off (if at all), I'd like to propose a useful idea: reusing > the AS keyword in a different context. > > Example: > > $x = $attributeReflection->newInstance() as MyAttribute; > > This would essentially perform the following code: > > assert(($x = $attributeReflection->newInstance()) instanceof MyAttribute); > > but would work even if assertions are disabled, and would provide some > sanity when working with mixed return types, or even dealing with > interfaces where you want to be sure you are dealing with a concrete > type: > > class Query implements QueryInterface {} > > function getQuery(string $sql): QueryInterface {} > > $x = getQuery("select 1 = 1") as Query; > > which is more like: > > assert(($x = getQuery("select 1 = 1")) instanceof Query); > > It'd also be nice to have a non-throwing version where we simply > specify that the type is nullable: > > $x = $attributeReflection->newInstance() as ?MyAttribute; > if ($x === null) // do something since the attribute isn't MyAttribute > > which is more like: > > try { > assert(($x = $attributeReflection->newInstance()) instanceof > MyAttribute); > } catch { > $x = null > } > > Or a more complex type: > > $x = $attributeReflection->newInstance() as > PretttyAttribute|(UglyAttribute&UtilityAttribute); > > Essentially, by using "as", you can be 100% sure that the type is the > expected type signature, null (if the type signature includes null), > or an error to be thrown. > > Note that this isn't casting from one type to another, but asserting > that this type is the type you expect. It'd significantly help with > static analysis, IDE code completion, etc. > > What do you think? > > Robert Landers > Software Engineer > Utrecht NL > What's the advantage of a language construct over the following? ```php /** * @template T of object * @psalm-assert T $value * @param class-string<T> $type */ function as(mixed $value, string $type): mixed { if (! $value instanceof $type) { throw SomeKindOfException::forMismatchingRequirements($value, $type); } return $value; } echo as(myExpression(), MyType::class)->methodOfMyType(); ``` See https://3v4l.org/iQPok See https://phpstan.org/r/708912d3-64e2-46f0-9f9e-467921a6489a See https://psalm.dev/r/7f30d63865 Note that `azjezz/psl` provides a very complete toolkit around this kind of tooling: https://github.com/azjezz/psl/tree/5f0aeacb708a33d5b2d53a832736c7767a99b215/src/Psl/Type One note: if what you are going for is what `azjezz/psl`, be aware that exception / error tracing design needs special attention here: it's not as simple as it looks! Marco Pivetta https://mastodon.social/@ocramius https://ocramius.github.io/