Repository: laravel/framework
File: src/Illuminate/View/Compilers/BladeCompiler.php (PHP)

Code before:

    /**
     * Register a handler for custom directives, binding the handler to the compiler.
     *
     * @param  string  $name
     * @param  callable  $handler
     * @return void
     *
     * @throws \InvalidArgumentException
     */
    public function bindDirective($name, callable $handler)
    {
        $this->directive($name, $handler, bind: true);
    }

    /**
     * Register a handler for custom directives.
     *
     * @param  string  $name
     * @param  \Closure  $handler
     * @param  bool  $bind
     * @return void
     *
     * @throws \InvalidArgumentException
     */
    public function directive($name, \Closure $handler, bool $bind = false)
    {
        if (! preg_match('/^\w+(?:::\w+)?$/x', $name)) {
            throw new InvalidArgumentException("The directive name [{$name}] is not valid. Directive names must only contain alphanumeric characters and underscores.");
        }

        $this->customDirectives[$name] = $bind ? $handler->bindTo($this, BladeCompiler::class) : $handler;
    }

    /**
     * Get the list of custom directives.
     *
     * @return array
     */
    public function getCustomDirectives()
    {
        return $this->customDirectives;
    }

    /**
     * Indicate that the following callable should be used to prepare strings for compilation.
     *
     * @param  callable  $callback
     * @return $this
     */
    public function prepareStringsForCompilationUsing(callable $callback)

Review comment (suggestion):
This would be a breaking change. Your intuition is correct, but an option could be keeping everything as `callable` and do a runtime check when `$bind` is true and `$handler` is a closure instance? In that scenario, an exception could be thrown. 

Not sure if there's a better way to handle that, or if it's even something the framework commonly validates

Code after:

    /**
     * Register a handler for custom directives, binding the handler to the compiler.
     *
     * @param  string  $name
     * @param  callable  $handler
     * @return void
     *
     * @throws \InvalidArgumentException
     */
    public function bindDirective($name, callable $handler)
    {
        $this->directive($name, $handler, bind: true);
    }

    /**
     * Register a handler for custom directives.
     *
     * @param  string  $name
     * @param  ($bind is true ? \Closure : callable)  $handler
     * @param  bool  $bind
     * @return void
     *
     * @throws \InvalidArgumentException
     */
    public function directive($name, callable $handler, bool $bind = false)
    {
        if (! preg_match('/^\w+(?:::\w+)?$/x', $name)) {
            throw new InvalidArgumentException("The directive name [{$name}] is not valid. Directive names must only contain alphanumeric characters and underscores.");
        }

        $this->customDirectives[$name] = $bind ? $handler->bindTo($this, BladeCompiler::class) : $handler;
    }

    /**
     * Get the list of custom directives.
     *
     * @return array
     */
    public function getCustomDirectives()
    {
        return $this->customDirectives;
    }

    /**
     * Indicate that the following callable should be used to prepare strings for compilation.
     *
     * @param  callable  $callback
     * @return $this
     */
    public function prepareStringsForCompilationUsing(callable $callback)