To make it easier to easily work with all the different hashing implementations that we have created in previous articles, we will create a new class called HashManager in some directory that is accessible with the namespace Laravel\Artisan\Hashing\HashManager.
The hashing articles were created in the following articles:
- Laravel: Implementing a CRYPT_STD_DES Hasher
- Laravel: Implementing a CRYPT_EXT_DES Hasher
- Laravel: Implementing a MD5 Hasher
- Laravel: Implementing a CRYPT_SHA256 Hasher
- Laravel: Implementing a CRYPT_SHA512 Hasher
- Creating a Service Provider For Our Custom laravel Hashing Implementations
The goal of this hashing manager class is to be able to write code that looks like the following:
 1<?php
 2
 3use Laravel\Artisan\Hashing\Hasher;
 4
 5// Make a hash with the default hasher.
 6$hash = Hasher::hash()->make('test');
 7
 8// Make a hash with our new hasher implementations.
 9$hash = Hasher::hashSha256()->make('test');
10$hash = Hasher::hashSha512()->make('test');
11$hash = Hasher::hashDes()->make('test');
12$hash = Hasher::hashExtDes()->make('test');
13$hash = Hasher::hashMd5()->make('test');
14
15// We should also be able to work with an instance.
16$hasher = new Hasher;
17$hash = $hasher->hashSha256()->make('test');
With the goals in mind we have a few options. We can explicitly create all the member and static methods, or we can find some way to dynamically call the methods. Luckily, PHP provides __call and __callStatic methods that we can take advantage of to achieve our goals.
The complete code for our new Hasher will look like this:
 1<?php
 2namespace Laravel\Artisan\Hashing;
 3
 4use Illuminate\Support\Str;
 5
 6class Hasher
 7{
 8
 9    /**
10     * Dynamically handle calls to the class.
11     *
12     * @param  string  $method
13     * @param  array   $parameters
14     * @return mixed
15     *
16     * @throws \BadMethodCallException
17     */
18    public function __call($method, $parameters)
19    {
20        // We will handle the case of 'hash' specially so that
21        // we can request the default hasher implementation.
22        if ($method == 'hash') {
23            return app('hash');
24        }
25
26        // Figure out which hasher to get from the service container.
27        // We will use mb_substr to remove the "with" part of the
28        // method name. This should leave us with some form
29        // of the actual hasher implementation name.
30        $hasher = mb_substr($method, 4);
31
32        // All the hashing implementations were bound to the service
33        // container using the format hash.camelCaseHashName. Now
34        // we just have to use the Str::camel() helper function.
35        $hasher = Str::camel($hasher);
36
37        // Now that we have the name in the form we can use, we
38        // can request the hasher instance from the service
39        // container and return it the user who wants it.
40        return app('hash.'.$hasher);
41    }
42
43    /**
44     * Handle dynamic, static calls to the object.
45     *
46     * @param  string  $method
47     * @param  array   $args
48     * @return mixed
49     */
50    public static function __callStatic($method, $args)
51    {
52        // Create a new instance and forward the method
53        // call to it. Not the most elegant solution
54        // but it really helps with code re-use.
55        $instance = new static;
56        return $instance->$method();
57    }
58
59}
We could create a facade for the Hasher, but is just another layer of indirection that is not needed in this particular case.
∎