Skip to content

callable parameter with any number of arguments #8214

Description

@ondrejmirtes

Feature request

From #6813

I recently tried to create something where this would have been quite useful: a higher-order function to take functions that throw exceptions, catch (and log) them, and then return a WP_Error object instead.

/**
 * Wraps a function so that, when run, any exceptions are caught, logged, and converted to a generic WP_Error.
 *
 * Works with functions of up to 5 parameters. (Add more PX generic types to this docblock to add support for more params.)
 *
 * @template P1
 * @template P2
 * @template P3
 * @template P4
 * @template P5
 * @template R
 *
 * @param (Closure(P1, P2, P3, P4, P5): R) $fn Function that could throw.
 *
 * @return (Closure(P1, P2, P3, P4, P5): (R|WP_Error))
 */
function handleExceptionsAsWpErrors(Closure $fn, LoggerInterface $logger): Closure {
	return static function (...$params) use ($fn, $logger) {
		try {
			return $fn(...$params);
		} catch (Throwable $e) {
			$logger->error($e->getMessage());
			return new WP_Error('arn_internal_server_error');
		}
	};
}

In this case, I was hoping that I could get around the issue of having variable numbers of params by hardcoding generics for a reasonable max number of parameters. My hope was that, that for Closures with less than 5 params, the unused PX template types would default to never, and Closure(never): R would be considered identical to Closure(): R.

Of course, it didn't actually work when I tried it, and I suspect that not even setting explicit defaults for the template types (once #1835 lands) would alter the behavior here.

But should it work? Is a parameter of type never the same thing as no parameter at all? Or would that conceptually be more like a void parameter, if such a thing even makes sense?


It's also worth noting that TypeScript has a Parameters utility type. Presumably, if PHPStan had something like this, the kind of static typing I'm looking for would be straightforward, using syntax that could look a little like this:

/**
 * @template R
 *
 * @param (Closure(...): R) $fn
 *
 * @return (Closure(...parameters<$fn>): (R|WP_Error))
 */

What do you think of these ideas?

Originally posted by @ZebulanStanphill in #6813 (comment)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions