Repository: pusher/pusher-http-php (php)

Issue:
[6.1] `build_auth_query_params()` returns array instead of string
As title says, this [PHPDoc says the function returns a string](https://github.com/pusher/pusher-http-php/blob/master/src/Pusher.php#L276-L299) while it returns an array.


Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
 # Changelog
 
+## 7.0.0
+
+* [DEPRECATED] `get_channel_info`, `get_channels`, `socket_auth`, `presence_auth` in favour of camelCased versions
+* [DEPRECATED] `get_users_info` in favour of `getPresenceUsers`
+* [DEPRECATED] `ensure_valid_signature` in favour of `verifySignature`
+* [CHANGED] Restrict `$app_id` parameter of the `Pusher()` object to `string` (`int` was possible).
+* [ADDED] Return types.
+* [ADDED] Namespacing, PSR-12 formatting.
+
 ## 6.1.0
 
 * [ADDED] triggerAsync and triggerBatchAsync using the Guzzle async interface.
@@ -14,7 +23,7 @@
 * [CHANGED] internal HTTP client to Guzzle
 * [ADDED] optional client parameter to constructor
 * [CHANGED] useTLS is true by default
-* [REMOVED]  from options
+* [REMOVED] `curl_options` from options
 * [REMOVED] customer logger
 * [REMOVED] host, port and timeout constructor parameters
 * [REMOVED] support for PHP 7.1
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -18,15 +18,15 @@ Or add to `composer.json`:
 
 ```json
 "require": {
-	"pusher/pusher-php-server": "^6.1"
+    "pusher/pusher-php-server": "^7.0"
 }
 ```
 
-and then run `composer update`.
+then run `composer update`.
 
 ## Supported platforms
 
-* PHP - supports PHP versions 7.2, 7.3, 7.4 and 8.0.
+* PHP - supports PHP versions 7.3, 7.4 and 8.0.
 * Laravel - version 8.29 and above has built-in support for Pusher Channels as a [Broadcasting backend](https://laravel.com/docs/master/broadcasting).
 * Other PHP frameworks - supported provided you are using a supported version of PHP.
 
@@ -40,7 +40,7 @@ $app_key = 'YOUR_APP_KEY';
 $app_secret = 'YOUR_APP_SECRET';
 $app_cluster = 'YOUR_APP_CLUSTER';
 
-$pusher = new Pusher\Pusher( $app_key, $app_secret, $app_id, array('cluster' => $app_cluster) );
+$pusher = new Pusher\Pusher($app_key, $app_secret, $app_id, ['cluster' => $app_cluster]);
 ```
 
 The fourth parameter is an `$options` array. The additional options are:
@@ -66,7 +66,7 @@ $options = [
   'cluster' => $app_cluster,
   'useTLS' => false
 ];
-$pusher = new Pusher\Pusher( $app_key, $app_secret, $app_id, $options );
+$pusher = new Pusher\Pusher($app_key, $app_secret, $app_id, $options);
 ```
 
 ## Logging configuration
@@ -92,12 +92,11 @@ your own Guzzle instance to the Pusher constructor:
 $custom_client = new GuzzleHttp\Client();
 
 $pusher = new Pusher\Pusher(
-	$app_key,
-	$app_secret,
-	$app_id,
-	array(),
-	$custom_client
-	)
+    $app_key,
+    $app_secret,
+    $app_id,
+    [],
+    $custom_client
 );
 ```
 
@@ -111,13 +110,13 @@ To trigger an event on one or more channels use the `trigger` function.
 ### A single channel
 
 ```php
-$pusher->trigger( 'my-channel', 'my_event', 'hello world' );
+$pusher->trigger('my-channel', 'my_event', 'hello world');
 ```
 
 ### Multiple channels
 
 ```php
-$pusher->trigger( [ 'channel-1', 'channel-2' ], 'my_event', 'hello world' );
+$pusher->trigger([ 'channel-1', 'channel-2' ], 'my_event', 'hello world');
 ```
 
 ### Batches
@@ -126,9 +125,9 @@ It's also possible to send multiple events with a single API call (max 10
 events per call on multi-tenant clusters):
 
 ```php
-$batch = array();
-$batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => array('hello' => 'world'));
-$batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => array('myname' => 'bob'));
+$batch = [];
+$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world']];
+$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob']];
 $pusher->triggerBatch($batch);
 ```
 
@@ -140,9 +139,9 @@ promises](https://github.com/guzzle/promises) which can be chained
 with `->then`:
 
 ```php
-$promise = $pusher->triggerAsync( [ 'channel-1', 'channel-2' ], 'my_event', 'hello world' );
+$promise = $pusher->triggerAsync(['channel-1', 'channel-2'], 'my_event', 'hello world');
 
-$promise->then(function ($result) {
+$promise->then(function($result) {
   // do something with $result
   return $result;
 });
@@ -152,7 +151,7 @@ $final_result = $promise->wait();
 
 ### Arrays
 
-Objects are automatically converted to JSON format:
+Arrays are automatically converted to JSON format:
 
 ```php
 $array['name'] = 'joe';
@@ -174,13 +173,13 @@ socket id](https://pusher.com/docs/channels/server_api/excluding-event-recipient
 while triggering an event:
 
 ```php
-$pusher->trigger('my-channel', 'event', 'data', array('socket_id' => $socket_id));
+$pusher->trigger('my-channel', 'event', 'data', ['socket_id' => $socket_id]);
 ```
 
 ```php
-$batch = array();
-$batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => array('hello' => 'world'), array('socket_id' => $socket_id));
-$batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => array('myname' => 'bob'), array('socket_id' => $socket_id);
+$batch = [];
+$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world'], ['socket_id' => $socket_id]];
+$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob'], ['socket_id' => $socket_id]];
 $pusher->triggerBatch($batch);
 ```
 
@@ -191,23 +190,23 @@ published to with the
 [`info` param](https://pusher.com/docs/channels/library_auth_reference/rest-api#request):
 
 ```php
-$result = $pusher->trigger('my-channel', 'my_event', 'hello world', array('info' => 'subscription_count'));
+$result = $pusher->trigger('my-channel', 'my_event', 'hello world', ['info' => 'subscription_count']);
 $subscription_count = $result->channels['my-channel']->subscription_count;
 ```
 
 ```php
-$batch = array();
-$batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => array('hello' => 'world'), 'info' => 'subscription_count');
-$batch[] = array('channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => array('myname' => 'bob'), 'info' => 'user_count,subscription_count');
+$batch = [];
+$batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => ['hello' => 'world'], 'info' => 'subscription_count'];
+$batch[] = ['channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => ['myname' => 'bob'], 'info' => 'user_count,subscription_count'];
 $result = $pusher->triggerBatch($batch);
 
 foreach ($result->batch as $i => $attributes) {
   echo "channel: {$batch[$i]['channel']}, name: {$batch[$i]['name']}";
   if (isset($attributes->subscription_count)) {
-	echo ", subscription_count: {$attributes->subscription_count}";
+    echo ", subscription_count: {$attributes->subscription_count}";
   }
   if (isset($attributes->user_count)) {
-	echo ", user_count: {$attributes->user_count}";
+    echo ", user_count: {$attributes->user_count}";
   }
   echo PHP_EOL;
 }
@@ -219,16 +218,16 @@ If your data is already encoded in JSON format, you can avoid a second encoding
 step by setting the sixth argument true, like so:
 
 ```php
-$pusher->trigger('my-channel', 'event', 'data', array(), true)
+$pusher->trigger('my-channel', 'event', 'data', [], true);
 ```
 
 ## Authenticating Private channels
 
 To authorise your users to access private channels on Pusher, you can use the
-`socket_auth` function:
+`socketAuth` function:
 
 ```php
-$pusher->socket_auth('private-my-channel','socket_id');
+$pusher->socketAuth('private-my-channel','socket_id');
 ```
 
 ## Authenticating Presence channels
@@ -237,7 +236,7 @@ Using presence channels is similar to private channels, but you can specify
 extra data to identify that particular user:
 
 ```php
-$pusher->presence_auth('presence-my-channel','socket_id', 'user_id', 'user_info');
+$pusher->presenceAuth('presence-my-channel','socket_id', 'user_id', 'user_info');
 ```
 
 ## Webhooks
@@ -252,7 +251,7 @@ exception is thrown instead.
 ```php
 $webhook = $pusher->webhook($request_headers, $request_body);
 $number_of_events = count($webhook->get_events());
-$time_recieved = $webhook->get_time_ms();
+$time_received = $webhook->get_time_ms();
 ```
 
 ## End to end encryption
@@ -281,14 +280,14 @@ these steps:
 
    ```php
    $pusher = new Pusher\Pusher(
-	   $app_key,
-	   $app_secret,
-	   $app_id,
-	   array(
-		   'cluster' => $app_cluster,
-		   'encryption_master_key_base64' => "<your base64 encoded master key>"
-	   )
-   );
+       $app_key,
+       $app_secret,
+       $app_id,
+       [
+           'cluster' => $app_cluster,
+           'encryption_master_key_base64' => "<your base64 encoded master key>"
+       ]
+    );
    ```
 
 4. Channels where you wish to use end to end encryption should be prefixed with
@@ -309,7 +308,7 @@ call to `trigger`, e.g.
 $data['name'] = 'joe';
 $data['message_count'] = 23;
 
-$pusher->trigger(array('channel-1', 'private-encrypted-channel-2'), 'test_event', $data);
+$pusher->trigger(['channel-1', 'private-encrypted-channel-2'], 'test_event', $data);
 ```
 
 Rationale: the methods in this library map directly to individual Channels HTTP
@@ -322,29 +321,30 @@ is unencrypted for unencrypted channels.
 
 First set this variable in your JS app:
 
-```php
-Pusher.channel_auth_endpoint = '/presence_auth.php';
+```js
+Pusher.channel_auth_endpoint = '/presenceAuth.php';
 ```
 
-Next, create the following in presence_auth.php:
+Next, create the following in presenceAuth.php:
 
 ```php
 <?php
+
+header('Content-Type: application/json');
+
 if (isset($_SESSION['user_id'])) {
   $stmt = $pdo->prepare("SELECT * FROM `users` WHERE id = :id");
   $stmt->bindValue(':id', $_SESSION['user_id'], PDO::PARAM_INT);
   $stmt->execute();
   $user = $stmt->fetch();
 } else {
-  die('aaargh, no-one is logged in');
+  die(json_encode('no-one is logged in'));
 }
 
-header('Content-Type: application/json');
-
 $pusher = new Pusher\Pusher($key, $secret, $app_id);
-$presence_data = array('name' => $user['name']);
+$presence_data = ['name' => $user['name']];
 
-echo $pusher->presence_auth($_POST['channel_name'], $_POST['socket_id'], $user['id'], $presence_data);
+echo $pusher->presenceAuth($_POST['channel_name'], $_POST['socket_id'], $user['id'], $presence_data);
 ```
 
 Note: this assumes that you store your users in a table called `users` and that
@@ -356,13 +356,13 @@ mechanism that stores the `user_id` of the logged in user in the session.
 ### Get information about a channel
 
 ```php
-$pusher->get_channel_info( $name );
+$pusher->getChannelInfo($name);
 ```
 
 It's also possible to get information about a channel from the Channels HTTP API.
 
 ```php
-$info = $pusher->get_channel_info('channel-name');
+$info = $pusher->getChannelInfo('channel-name');
 $channel_occupied = $info->occupied;
 ```
 
@@ -371,7 +371,7 @@ query the number of distinct users currently subscribed to this channel (a
 single user may be subscribed many times, but will only count as one):
 
 ```php
-$info = $pusher->get_channel_info('presence-channel-name', array('info' => 'user_count'));
+$info = $pusher->getChannelInfo('presence-channel-name', ['info' => 'user_count']);
 $user_count = $info->user_count;
 ```
 
@@ -380,28 +380,28 @@ of connections currently subscribed to this channel) then you can query this
 value as follows:
 
 ```php
-$info = $pusher->get_channel_info('presence-channel-name', array('info' => 'subscription_count'));
+$info = $pusher->getChannelInfo('presence-channel-name', ['info' => 'subscription_count']);
 $subscription_count = $info->subscription_count;
 ```
 
 ### Get a list of application channels
 
 ```php
-$pusher->get_channels()
+$pusher->getChannels();
 ```
 
 It's also possible to get a list of channels for an application from the
 Channels HTTP API.
 
 ```php
-$result = $pusher->get_channels();
+$result = $pusher->getChannels();
 $channel_count = count($result->channels); // $channels is an Array
 ```
 
 ### Get a filtered list of application channels
 
 ```php
-$pusher->get_channels( array( 'filter_by_prefix' => 'some_filter' ) )
+$pusher->getChannels(['filter_by_prefix' => 'some_filter']);
 ```
 
 It's also possible to get a list of channels based on their name prefix. To do
@@ -410,30 +410,31 @@ example the call will return a list of all channels with a `presence-` prefix.
 This is idea for fetching a list of all presence channels.
 
 ```php
-$results = $pusher->get_channels( array( 'filter_by_prefix' => 'presence-') );
+$results = $pusher->getChannels(['filter_by_prefix' => 'presence-']);
 $channel_count = count($result->channels); // $channels is an Array
 ```
 
 This can also be achieved using the generic `pusher->get` function:
 
 ```php
-$pusher->get( '/channels', array( 'filter_by_prefix' => 'presence-' ) );
+$pusher->get('/channels', ['filter_by_prefix' => 'presence-']);
 ```
 
 ### Get a list of application channels with subscription counts
 
 The HTTP API returning the channel list does not support returning the
 subscription count along with each channel. Instead, you can fetch this data by
-iterating over each channel and making another request. But be warned: this
+iterating over each channel and making another request. Be warned: this
 approach consumes (number of channels + 1) messages!
 
 ```php
 <?php
-$subscription_counts = array();
-foreach ($pusher->get_channels()->channels as $channel => $v) {
+$subscription_counts = [];
+foreach ($pusher->getChannels()->channels as $channel => $v) {
   $subscription_counts[$channel] =
-	$pusher->get_channel_info(
-	  $channel, array('info' => 'subscription_count'))->subscription_count;
+    $pusher->getChannelInfo(
+      $channel, ['info' => 'subscription_count']
+    )->subscription_count;
 }
 var_dump($subscription_counts);
 ```
@@ -441,14 +442,14 @@ var_dump($subscription_counts);
 ### Get user information from a presence channel
 
 ```php
-$results = $pusher->get_users_info( 'presence-channel-name' );
+$results = $pusher->getPresenceUsers('presence-channel-name');
 $users_count = count($results->users); // $users is an Array
 ```
 
 This can also be achieved using the generic `pusher->get` function:
 
 ```php
-$response = $pusher->get( '/channels/presence-channel-name/users' )
+$response = $pusher->get('/channels/presence-channel-name/users');
 ```
 
 The `$response` is in the format:
@@ -471,7 +472,7 @@ Array (
 ### Generic get function
 
 ```php
-$pusher->get( $path, $params );
+$pusher->get($path, $params);
 ```
 
 Used to make `GET` queries against the Channels HTTP API. Handles authentication.
@@ -482,9 +483,9 @@ property to allow the HTTP status code is always present and a `result`
 property will be set if the status code indicates a successful call to the API.
 
 ```php
-$response = $pusher->get( '/channels' );
-$http_status_code = $response[ 'status' ];
-$result = $response[ 'result' ];
+$response = $pusher->get('/channels');
+$http_status_code = $response['status'];
+$result = $response['result'];
 ```
 
 ## Running the tests
diff --git a/composer.json b/composer.json
--- a/composer.json
+++ b/composer.json
@@ -4,14 +4,15 @@
     "keywords": ["php-pusher-server", "pusher", "rest", "realtime", "real-time", "real time", "messaging", "push", "trigger", "publish", "events"],
     "license": "MIT",
     "require": {
-        "php": "^7.2.5|^8.0",
+        "php": "^7.3|^8.0",
         "ext-curl": "*",
+        "ext-json": "*",
         "guzzlehttp/guzzle": "^7.2",
         "psr/log": "^1.0",
         "paragonie/sodium_compat": "^1.6"
     },
     "require-dev": {
-        "phpunit/phpunit": "^7.2|^8.5|^9.3",
+        "phpunit/phpunit": "^8.5|^9.3",
         "overtrue/phplint": "^2.3"
     },
     "autoload": {
diff --git a/src/ApiErrorException.php b/src/ApiErrorException.php
--- a/src/ApiErrorException.php
+++ b/src/ApiErrorException.php
@@ -14,7 +14,7 @@ class ApiErrorException extends PusherException
      *
      * @return string
      */
-    public function __toString()
+    public function __toString(): string
     {
         return "(Status {$this->getCode()}) {$this->getMessage()}";
     }
diff --git a/src/Pusher.php b/src/Pusher.php
--- a/src/Pusher.php
+++ b/src/Pusher.php
@@ -2,6 +2,8 @@
 
 namespace Pusher;
 
+use GuzzleHttp\ClientInterface;
+use GuzzleHttp\Exception\GuzzleException;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
 use Psr\Log\LoggerInterface;
@@ -16,7 +18,7 @@ class Pusher implements LoggerAwareInterface, PusherInterface
     /**
      * @var string Version
      */
-    public static $VERSION = '6.1.0';
+    public static $VERSION = '7.0.0';
 
     /**
      * @var null|PusherCrypto
@@ -26,12 +28,12 @@ class Pusher implements LoggerAwareInterface, PusherInterface
     /**
      * @var array Settings
      */
-    private $settings = array(
+    private $settings = [
         'scheme'                => 'http',
         'port'                  => 80,
         'path'                  => '',
         'timeout'               => 30,
-    );
+    ];
 
     /**
      * @var null|resource
@@ -43,8 +45,8 @@ class Pusher implements LoggerAwareInterface, PusherInterface
      *
      * @param string $auth_key
      * @param string $secret
-     * @param int    $app_id
-     * @param array  $options  [optional]
+     * @param string $app_id
+     * @param array $options  [optional]
      *                         Options to configure the Pusher instance.
      *                         scheme - e.g. http or https
      *                         host - the host e.g. api-mt1.pusher.com. No trailing forward slash.
@@ -53,11 +55,11 @@ class Pusher implements LoggerAwareInterface, PusherInterface
      *                         useTLS - quick option to use scheme of https and port 443 (default is true).
      *                         cluster - cluster name to connect to.
      *                         encryption_master_key_base64 - a 32 byte key, encoded as base64. This key, along with the channel name, are used to derive per-channel encryption keys. Per-channel keys are used to encrypt event data on encrypted channels.
-     * @param client $resource [optional] - a Guzzle client to use for all HTTP requests
+     * @param ClientInterface|null $client [optional] - a Guzzle client to use for all HTTP requests
      *
      * @throws PusherException Throws exception if any required dependencies are missing
      */
-    public function __construct($auth_key, $secret, $app_id, $options = array(), $client = null)
+    public function __construct(string $auth_key, string $secret, string $app_id, array $options = [], ClientInterface $client = null)
     {
         $this->check_compatibility();
 
@@ -83,7 +85,7 @@ public function __construct($auth_key, $secret, $app_id, $options = array(), $cl
         $this->settings['auth_key'] = $auth_key;
         $this->settings['secret'] = $secret;
         $this->settings['app_id'] = $app_id;
-        $this->settings['base_path'] = '/apps/'.$this->settings['app_id'];
+        $this->settings['base_path'] = '/apps/' . $this->settings['app_id'];
 
         foreach ($options as $key => $value) {
             // only set if valid setting/option
@@ -97,7 +99,7 @@ public function __construct($auth_key, $secret, $app_id, $options = array(), $cl
             if (array_key_exists('host', $options)) {
                 $this->settings['host'] = $options['host'];
             } elseif (array_key_exists('cluster', $options)) {
-                $this->settings['host'] = 'api-'.$options['cluster'].'.pusher.com';
+                $this->settings['host'] = 'api-' . $options['cluster'] . '.pusher.com';
             } else {
                 $this->settings['host'] = 'api-mt1.pusher.com';
             }
@@ -110,7 +112,7 @@ public function __construct($auth_key, $secret, $app_id, $options = array(), $cl
             $options['encryption_master_key_base64'] = '';
         }
 
-        if ($options['encryption_master_key_base64'] != '') {
+        if ($options['encryption_master_key_base64'] !== '') {
             $parsedKey = PusherCrypto::parse_master_key(
                 $options['encryption_master_key_base64']
             );
@@ -123,7 +125,7 @@ public function __construct($auth_key, $secret, $app_id, $options = array(), $cl
      *
      * @return array
      */
-    public function getSettings()
+    public function getSettings(): array
     {
         return $this->settings;
     }
@@ -134,10 +136,8 @@ public function getSettings()
      * @param string           $msg     The message to log
      * @param array|\Exception $context [optional] Any extraneous information that does not fit well in a string.
      * @param string           $level   [optional] Importance of log message, highly recommended to use Psr\Log\LogLevel::{level}
-     *
-     * @return void
      */
-    private function log($msg, array $context = array(), $level = LogLevel::DEBUG)
+    private function log(string $msg, array $context = [], string $level = LogLevel::DEBUG): void
     {
         if (is_null($this->logger)) {
             return;
@@ -151,29 +151,27 @@ private function log($msg, array $context = array(), $level = LogLevel::DEBUG)
 
         // Support old style logger (deprecated)
         $msg = sprintf('Pusher: %s: %s', strtoupper($level), $msg);
-        $replacement = array();
+        $replacement = [];
 
         foreach ($context as $k => $v) {
-            $replacement['{'.$k.'}'] = $v;
+            $replacement['{' . $k . '}'] = $v;
         }
 
-        $this->logger->log(strtr($msg, $replacement));
+        $this->logger->log($level, strtr($msg, $replacement));
     }
 
     /**
      * Check if the current PHP setup is sufficient to run this class.
      *
      * @throws PusherException If any required dependencies are missing
-     *
-     * @return void
      */
-    private function check_compatibility()
+    private function check_compatibility(): void
     {
         if (!extension_loaded('json')) {
             throw new PusherException('The Pusher library requires the PHP JSON module. Please ensure it is installed');
         }
 
-        if (!in_array('sha256', hash_algos())) {
+        if (!in_array('sha256', hash_algos(), true)) {
             throw new PusherException('SHA256 appears to be unsupported - make sure you have support for it, or upgrade your version of PHP.');
         }
     }
@@ -184,10 +182,8 @@ private function check_compatibility()
      * @param string[] $channels An array of channel names to validate
      *
      * @throws PusherException If $channels is too big or any channel is invalid
-     *
-     * @return void
      */
-    private function validate_channels($channels)
+    private function validate_channels(array $channels): void
     {
         if (count($channels) > 100) {
             throw new PusherException('An event can be triggered on a maximum of 100 channels in a single call.');
@@ -204,13 +200,11 @@ private function validate_channels($channels)
      * @param string $channel The channel name to validate
      *
      * @throws PusherException If $channel is invalid
-     *
-     * @return void
      */
-    private function validate_channel($channel)
+    private function validate_channel(string $channel): void
     {
         if (!preg_match('/\A[-a-zA-Z0-9_=@,.;]+\z/', $channel)) {
-            throw new PusherException('Invalid channel name '.$channel);
+            throw new PusherException('Invalid channel name ' . $channel);
         }
     }
 
@@ -221,33 +215,31 @@ private function validate_channel($channel)
      *
      * @throws PusherException If $socket_id is invalid
      */
-    private function validate_socket_id($socket_id)
+    private function validate_socket_id(string $socket_id): void
     {
         if ($socket_id !== null && !preg_match('/\A\d+\.\d+\z/', $socket_id)) {
-            throw new PusherException('Invalid socket ID '.$socket_id);
+            throw new PusherException('Invalid socket ID ' . $socket_id);
         }
     }
 
     /**
      * Utility function used to generate signing headers
      *
-     * @param string            $path
-     * @param string [optional] $request_method
-     * @param array [optional]  $query_params
+     * @param string $path
+     * @param string $request_method
+     * @param array $query_params [optional]
      *
      * @return array
      */
-    private function sign($path, $request_method = 'GET', $query_params = array())
+    private function sign(string $path, string $request_method = 'GET', array $query_params = []): array
     {
-        $signed_params = self::build_auth_query_params(
+        return self::build_auth_query_params(
             $this->settings['auth_key'],
             $this->settings['secret'],
             $request_method,
             $path,
             $query_params
         );
-
-        return $signed_params;
     }
 
     /**
@@ -255,9 +247,9 @@ private function sign($path, $request_method = 'GET', $query_params = array())
      *
      * @return string
      */
-    private function channels_url_prefix()
+    private function channels_url_prefix(): string
     {
-        return $this->settings['scheme'].'://'.$this->settings['host'].':'.$this->settings['port'].$this->settings['path'];
+        return $this->settings['scheme'] . '://' . $this->settings['host'] . ':' . $this->settings['port'] . $this->settings['path'];
     }
 
     /**
@@ -267,22 +259,21 @@ private function channels_url_prefix()
      * @param string $auth_secret
      * @param string $request_method
      * @param string $request_path
-     * @param array  $query_params   [optional]
-     * @param string $auth_version   [optional]
-     * @param string $auth_timestamp [optional]
-     *
-     * @return string
+     * @param array $query_params [optional]
+     * @param string $auth_version [optional]
+     * @param string|null $auth_timestamp [optional]
+     * @return array
      */
     public static function build_auth_query_params(
-        $auth_key,
-        $auth_secret,
-        $request_method,
-        $request_path,
-        $query_params = array(),
-        $auth_version = '1.0',
-        $auth_timestamp = null
-    ) {
-        $params = array();
+        string $auth_key,
+        string $auth_secret,
+        string $request_method,
+        string $request_path,
+        array $query_params = [],
+        string $auth_version = '1.0',
+        string $auth_timestamp = null
+    ): array {
+        $params = [];
         $params['auth_key'] = $auth_key;
         $params['auth_timestamp'] = (is_null($auth_timestamp) ? time() : $auth_timestamp);
         $params['auth_version'] = $auth_version;
@@ -290,7 +281,7 @@ public static function build_auth_query_params(
         $params = array_merge($params, $query_params);
         ksort($params);
 
-        $string_to_sign = "$request_method\n".$request_path."\n".self::array_implode('=', '&', $params);
+        $string_to_sign = "$request_method\n" . $request_path . "\n" . self::array_implode('=', '&', $params);
 
         $auth_signature = hash_hmac('sha256', $string_to_sign, $auth_secret, false);
 
@@ -310,13 +301,13 @@ public static function build_auth_query_params(
      *
      * @return string The imploded array
      */
-    public static function array_implode($glue, $separator, $array)
+    public static function array_implode(string $glue, string $separator, $array): string
     {
         if (!is_array($array)) {
             return $array;
         }
 
-        $string = array();
+        $string = [];
         foreach ($array as $key => $val) {
             if (is_array($val)) {
                 $val = implode(',', $val);
@@ -331,21 +322,19 @@ public static function array_implode($glue, $separator, $array)
      * Helper function to prepare trigger request. Takes the same
      * parameters as the public trigger functions.
      *
-     * @param array|string $channels        A channel name or an array of channel names to publish the event on.
-     * @param string       $event
-     * @param mixed        $data            Event data
-     * @param array        $params          [optional]
-     * @param bool         $already_encoded [optional]
-     *
-     * @throws PusherException   Throws PusherException if $channels is an array of size 101 or above or $socket_id is invalid
-     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
-     * @throws GuzzleException
+     * @param array|string $channels A channel name or an array of channel names to publish the event on.
+     * @param string $event
+     * @param mixed $data Event data
+     * @param array $params [optional]
+     * @param bool $already_encoded [optional]
      *
+     * @return Request
+     * @throws PusherException Throws PusherException if $channels is an array of size 101 or above or $socket_id is invalid
      */
-    public function make_request($channels, $event, $data, $params = array(), $already_encoded = false) : Request
+    public function make_request($channels, string $event, $data, array $params = [], bool $already_encoded = false): Request
     {
         if (is_string($channels) === true) {
-            $channels = array($channels);
+            $channels = [$channels];
         }
 
         $this->validate_channels($channels);
@@ -366,31 +355,46 @@ public function make_request($channels, $event, $data, $params = array(), $alrea
                 // For rationale, see limitations of end-to-end encryption in the README
                 throw new PusherException('You cannot trigger to multiple channels when using encrypted channels');
             } else {
-                $data_encoded = $this->crypto->encrypt_payload($channels[0], $already_encoded ? $data : json_encode($data));
+                try {
+                    $data_encoded = $this->crypto->encrypt_payload(
+                        $channels[0],
+                        $already_encoded ? $data : json_encode($data, JSON_THROW_ON_ERROR)
+                    );
+                } catch (\JsonException $e) {
+                    throw new PusherException('Data encoding error.');
+                }
             }
         } else {
-            $data_encoded = $already_encoded ? $data : json_encode($data);
+            try {
+                $data_encoded = $already_encoded ? $data : json_encode($data, JSON_THROW_ON_ERROR);
+            } catch (\JsonException $e) {
+                throw new PusherException('Data encoding error.');
+            }
         }
 
-        $query_params = array();
+        $query_params = [];
 
-        $path = $this->settings['base_path'].'/events';
+        $path = $this->settings['base_path'] . '/events';
 
         // json_encode might return false on failure
         if (!$data_encoded) {
-            $this->log('Failed to perform json_encode on the the provided data: {error}', array(
+            $this->log('Failed to perform json_encode on the the provided data: {error}', [
                 'error' => print_r($data, true),
-            ), LogLevel::ERROR);
+            ], LogLevel::ERROR);
         }
 
-        $post_params = array();
+        $post_params = [];
         $post_params['name'] = $event;
         $post_params['data'] = $data_encoded;
         $post_params['channels'] = array_values($channels);
 
         $all_params = array_merge($post_params, $params);
 
-        $post_value = json_encode($all_params);
+        try {
+            $post_value = json_encode($all_params, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
 
         $query_params['body_md5'] = md5($post_value);
 
@@ -400,33 +404,32 @@ public function make_request($channels, $event, $data, $params = array(), $alrea
 
         $headers = [
             'Content-Type' => 'application/json',
-            'X-Pusher-Library' => 'pusher-http-php '.self::$VERSION
+            'X-Pusher-Library' => 'pusher-http-php ' . self::$VERSION
         ];
 
         $params = array_merge($signature, $query_params);
         $query_string = self::array_implode('=', '&', $params);
-        $full_path = $path."?".$query_string;
-        $request = new Request('POST', $full_path, $headers, $post_value);
-
-        return $request;
+        $full_path = $path . "?" . $query_string;
+        return new Request('POST', $full_path, $headers, $post_value);
     }
 
     /**
      * Trigger an event by providing event name and payload.
      * Optionally provide a socket ID to exclude a client (most likely the sender).
      *
-     * @param array|string $channels        A channel name or an array of channel names to publish the event on.
-     * @param string       $event
-     * @param mixed        $data            Event data
-     * @param array        $params          [optional]
-     * @param bool         $already_encoded [optional]
+     * @param array|string $channels A channel name or an array of channel names to publish the event on.
+     * @param string $event
+     * @param mixed $data Event data
+     * @param array $params [optional]
+     * @param bool $already_encoded [optional]
      *
-     * @throws PusherException   Throws PusherException if $channels is an array of size 101 or above or $socket_id is invalid
+     * @return object
      * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
      * @throws GuzzleException
-     *
+     * @throws PusherException Throws PusherException if $channels is an array of size 101 or above or $socket_id is invalid
      */
-    public function trigger($channels, $event, $data, $params = array(), $already_encoded = false) : object {
+    public function trigger($channels, string $event, $data, array $params = [], bool $already_encoded = false): object
+    {
         $request = $this->make_request($channels, $event, $data, $params, $already_encoded);
 
         $response = $this->client->send($request, [
@@ -441,7 +444,11 @@ public function trigger($channels, $event, $data, $params = array(), $already_en
             throw new ApiErrorException($body, $status);
         }
 
-        $result = json_decode($response->getBody());
+        try {
+            $result = json_decode($response->getBody(), false, 512, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
 
         if (property_exists($result, 'channels')) {
             $result->channels = get_object_vars($result->channels);
@@ -454,14 +461,16 @@ public function trigger($channels, $event, $data, $params = array(), $already_en
      * Asynchronously trigger an event by providing event name and payload.
      * Optionally provide a socket ID to exclude a client (most likely the sender).
      *
-     * @param array|string $channels        A channel name or an array of channel names to publish the event on.
-     * @param string       $event
-     * @param mixed        $data            Event data
-     * @param array        $params          [optional]
-     * @param bool         $already_encoded [optional]
+     * @param array|string $channels A channel name or an array of channel names to publish the event on.
+     * @param string $event
+     * @param mixed $data Event data
+     * @param array $params [optional]
+     * @param bool $already_encoded [optional]
      *
+     * @return PromiseInterface
+     * @throws PusherException
      */
-    public function triggerAsync($channels, $event, $data, $params = array(), $already_encoded = false) : PromiseInterface
+    public function triggerAsync($channels, string $event, $data, array $params = [], bool $already_encoded = false): PromiseInterface
     {
         $request = $this->make_request($channels, $event, $data, $params, $already_encoded);
 
@@ -476,7 +485,7 @@ public function triggerAsync($channels, $event, $data, $params = array(), $alrea
                 throw new ApiErrorException($body, $status);
             }
 
-            $result = json_decode($response->getBody());
+            $result = json_decode($response->getBody(), null, 512, JSON_THROW_ON_ERROR);
 
             if (property_exists($result, 'channels')) {
                 $result->channels = get_object_vars($result->channels);
@@ -491,13 +500,13 @@ public function triggerAsync($channels, $event, $data, $params = array(), $alrea
     /**
      * Helper function to prepare batch trigger request. Takes the same                                                                                                                                               * parameters as the public batch trigger functions.
      *
-     * @param array $batch           [optional] An array of events to send
-     * @param bool  $already_encoded [optional]
+     * @param array $batch [optional] An array of events to send
+     * @param bool $already_encoded [optional]
      *
-     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
-     *
-     **/
-    public function make_batch_request($batch = array(), $already_encoded = false) : Request
+     * @return Request
+     * @throws PusherException
+     */
+    public function make_batch_request(array $batch = [], bool $already_encoded = false): Request
     {
         foreach ($batch as $key => $event) {
             $this->validate_channel($event['channel']);
@@ -507,7 +516,11 @@ public function make_batch_request($batch = array(), $already_encoded = false) :
 
             $data = $event['data'];
             if (!is_string($data)) {
-                $data = $already_encoded ? $data : json_encode($data);
+                try {
+                    $data = $already_encoded ? $data : json_encode($data, JSON_THROW_ON_ERROR);
+                } catch (\JsonException $e) {
+                    throw new PusherException('Data encoding error.');
+                }
             }
 
             if (PusherCrypto::is_encrypted_channel($event['channel'])) {
@@ -517,13 +530,17 @@ public function make_batch_request($batch = array(), $already_encoded = false) :
             }
         }
 
-        $post_params = array();
+        $post_params = [];
         $post_params['batch'] = $batch;
-        $post_value = json_encode($post_params);
+        try {
+            $post_value = json_encode($post_params, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
 
-        $query_params = array();
+        $query_params = [];
         $query_params['body_md5'] = md5($post_value);
-        $path = $this->settings['base_path'].'/batch_events';
+        $path = $this->settings['base_path'] . '/batch_events';
 
         $signature = $this->sign($path, 'POST', $query_params);
 
@@ -531,28 +548,27 @@ public function make_batch_request($batch = array(), $already_encoded = false) :
 
         $headers = [
             'Content-Type' => 'application/json',
-            'X-Pusher-Library' => 'pusher-http-php '.self::$VERSION
+            'X-Pusher-Library' => 'pusher-http-php ' . self::$VERSION
         ];
 
         $params = array_merge($signature, $query_params);
         $query_string = self::array_implode('=', '&', $params);
-        $full_path = $path."?".$query_string;
-        $request = new Request('POST', $full_path, $headers, $post_value);
-
-        return $request;
+        $full_path = $path . "?" . $query_string;
+        return new Request('POST', $full_path, $headers, $post_value);
     }
 
     /**
      * Trigger multiple events at the same time.
      *
-     * @param array $batch           [optional] An array of events to send
-     * @param bool  $already_encoded [optional]
+     * @param array $batch [optional] An array of events to send
+     * @param bool $already_encoded [optional]
      *
+     * @return object
      * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
      * @throws GuzzleException
-     *
+     * @throws PusherException
      */
-    public function triggerBatch($batch = array(), $already_encoded = false) : object
+    public function triggerBatch(array $batch = [], bool $already_encoded = false): object
     {
         $request = $this->make_batch_request($batch, $already_encoded);
 
@@ -568,7 +584,11 @@ public function triggerBatch($batch = array(), $already_encoded = false) : objec
             throw new ApiErrorException($body, $status);
         }
 
-        $result = json_decode($response->getBody());
+        try {
+            $result = json_decode($response->getBody(), false, 512, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
 
         if (property_exists($result, 'channels')) {
             $result->channels = get_object_vars($result->channels);
@@ -580,13 +600,13 @@ public function triggerBatch($batch = array(), $already_encoded = false) : objec
     /**
      * Asynchronously trigger multiple events at the same time.
      *
-     * @param array $batch           [optional] An array of events to send
-     * @param bool  $already_encoded [optional]
-     *
-     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
+     * @param array $batch [optional] An array of events to send
+     * @param bool $already_encoded [optional]
      *
+     * @return PromiseInterface
+     * @throws PusherException
      */
-    public function triggerBatchAsync($batch = array(), $already_encoded = false) : PromiseInterface
+    public function triggerBatchAsync(array $batch = [], bool $already_encoded = false): PromiseInterface
     {
         $request = $this->make_batch_request($batch, $already_encoded);
 
@@ -601,7 +621,7 @@ public function triggerBatchAsync($batch = array(), $already_encoded = false) :
                 throw new ApiErrorException($body, $status);
             }
 
-            $result = json_decode($response->getBody());
+            $result = json_decode($response->getBody(), false, 512, JSON_THROW_ON_ERROR);
 
             if (property_exists($result, 'channels')) {
                 $result->channels = get_object_vars($result->channels);
@@ -611,7 +631,6 @@ public function triggerBatchAsync($batch = array(), $already_encoded = false) :
         });
 
         return $promise;
-
     }
 
     /**
@@ -625,11 +644,19 @@ public function triggerBatchAsync($batch = array(), $already_encoded = false) :
      * @throws GuzzleException
      *
      */
-    public function get_channel_info($channel, $params = array()) : object
+    public function getChannelInfo(string $channel, array $params = []): object
     {
         $this->validate_channel($channel);
 
-        return $this->get('/channels/'.$channel, $params);
+        return $this->get('/channels/' . $channel, $params);
+    }
+
+    /**
+     * @deprecated in favour of getChannelInfo
+     */
+    public function get_channel_info(string $channel, array $params = []): object
+    {
+        return $this->getChannelInfo($channel, $params);
     }
 
     /**
@@ -641,7 +668,7 @@ public function get_channel_info($channel, $params = array()) : object
      * @throws GuzzleException
      *
      */
-    public function get_channels($params = array()) : object
+    public function getChannels(array $params = []): object
     {
         $result = $this->get('/channels', $params);
 
@@ -650,6 +677,14 @@ public function get_channels($params = array()) : object
         return $result;
     }
 
+    /**
+     * @deprecated in favour of getChannels
+     */
+    public function get_channels(array $params = []): object
+    {
+        return $this->getChannels($params);
+    }
+
     /**
      * Fetch user ids currently subscribed to a presence channel.
      *
@@ -659,9 +694,17 @@ public function get_channels($params = array()) : object
      * @throws GuzzleException
      *
      */
-    public function get_users_info($channel) : object
+    public function getPresenceUsers(string $channel): object
+    {
+        return $this->get('/channels/' . $channel . '/users');
+    }
+
+    /**
+     * @deprecated in favour of getPresenceUsers
+     */
+    public function get_users_info(string $channel): object
     {
-        return $this->get('/channels/'.$channel.'/users');
+        return $this->getPresenceUsers($channel);
     }
 
     /**
@@ -674,18 +717,19 @@ public function get_users_info($channel) : object
      *
      * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
      * @throws GuzzleException
+     * @throws PusherException
      *
      * @return mixed See Pusher API docs
      */
-    public function get($path, $params = array(), $associative = false)
+    public function get(string $path, array $params = [], $associative = false)
     {
-        $path = $this->settings['base_path'].$path;
+        $path = $this->settings['base_path'] . $path;
 
         $signature = $this->sign($path, 'GET', $params);
 
         $headers = [
             'Content-Type' => 'application/json',
-            'X-Pusher-Library' => 'pusher-http-php '.self::$VERSION
+            'X-Pusher-Library' => 'pusher-http-php ' . self::$VERSION
         ];
 
         $response = $this->client->get($path, [
@@ -702,7 +746,13 @@ public function get($path, $params = array(), $associative = false)
             throw new ApiErrorException($body, $status);
         }
 
-        return json_decode($response->getBody(), $associative);
+        try {
+            $body = json_decode($response->getBody(), $associative, 512, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data decoding error.');
+        }
+
+        return $body;
     }
 
     /**
@@ -710,24 +760,23 @@ public function get($path, $params = array(), $associative = false)
      *
      * @param string $channel
      * @param string $socket_id
-     * @param string $custom_data
-     *
-     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
+     * @param string|null $custom_data
      *
      * @return string Json encoded authentication string.
+     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
      */
-    public function socket_auth($channel, $socket_id, $custom_data = null) : string
+    public function socketAuth(string $channel, string $socket_id, string $custom_data = null): string
     {
         $this->validate_channel($channel);
         $this->validate_socket_id($socket_id);
 
         if ($custom_data) {
-            $signature = hash_hmac('sha256', $socket_id.':'.$channel.':'.$custom_data, $this->settings['secret'], false);
+            $signature = hash_hmac('sha256', $socket_id . ':' . $channel . ':' . $custom_data, $this->settings['secret'], false);
         } else {
-            $signature = hash_hmac('sha256', $socket_id.':'.$channel, $this->settings['secret'], false);
+            $signature = hash_hmac('sha256', $socket_id . ':' . $channel, $this->settings['secret'], false);
         }
 
-        $signature = array('auth' => $this->settings['auth_key'].':'.$signature);
+        $signature = ['auth' => $this->settings['auth_key'] . ':' . $signature];
         // add the custom data if it has been supplied
         if ($custom_data) {
             $signature['channel_data'] = $custom_data;
@@ -741,7 +790,21 @@ public function socket_auth($channel, $socket_id, $custom_data = null) : string
             }
         }
 
-        return json_encode($signature, JSON_UNESCAPED_SLASHES);
+        try {
+            $response = json_encode($signature, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
+
+        return $response;
+    }
+
+    /**
+     * @deprecated in favour of socketAuth
+     */
+    public function socket_auth(string $channel, string $socket_id, string $custom_data = null): string
+    {
+        return $this->socketAuth($channel, $socket_id, $custom_data);
     }
 
     /**
@@ -750,19 +813,31 @@ public function socket_auth($channel, $socket_id, $custom_data = null) : string
      * @param string $channel
      * @param string $socket_id
      * @param string $user_id
-     * @param mixed  $user_info
+     * @param mixed $user_info
      *
+     * @return string
      * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
-     *
      */
-    public function presence_auth($channel, $socket_id, $user_id, $user_info = null) : string
+    public function presenceAuth(string $channel, string $socket_id, string $user_id, $user_info = null): string
     {
-        $user_data = array('user_id' => $user_id);
+        $user_data = ['user_id' => $user_id];
         if ($user_info) {
             $user_data['user_info'] = $user_info;
         }
 
-        return $this->socket_auth($channel, $socket_id, json_encode($user_data));
+        try {
+            return $this->socket_auth($channel, $socket_id, json_encode($user_data, JSON_THROW_ON_ERROR));
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
+    }
+
+    /**
+     * @deprecated in favour of presenceAuth
+     */
+    public function presence_auth(string $channel, string $socket_id, string $user_id, $user_info = null): string
+    {
+        return $this->presence_auth($channel, $socket_id, $user_id, $user_info);
     }
 
     /**
@@ -775,33 +850,37 @@ public function presence_auth($channel, $socket_id, $user_id, $user_info = null)
      *
      * @return Webhook marshalled object with the properties time_ms (an int) and events (an array of event objects)
      */
-    public function webhook($headers, $body) : object
+    public function webhook(array $headers, string $body): object
     {
         $this->ensure_valid_signature($headers, $body);
 
-        $decoded_events = array();
-        $decoded_json = json_decode($body);
+        $decoded_events = [];
+        try {
+            $decoded_json = json_decode($body, false, 512, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            $this->log('Unable to decrypt webhook event payload.', null, LogLevel::WARNING);
+            throw new PusherException('Data encoding error.');
+        }
+
         foreach ($decoded_json->events as $key => $event) {
             if (PusherCrypto::is_encrypted_channel($event->channel)) {
                 if (!is_null($this->crypto)) {
                     $decryptedEvent = $this->crypto->decrypt_event($event);
 
-                    if ($decryptedEvent == false) {
+                    if ($decryptedEvent === false) {
                         $this->log('Unable to decrypt webhook event payload. Wrong key? Ignoring.', null, LogLevel::WARNING);
                         continue;
                     }
-                    array_push($decoded_events, $decryptedEvent);
+                    $decoded_events[] = $decryptedEvent;
                 } else {
                     $this->log('Got an encrypted webhook event payload, but no master key specified. Ignoring.', null, LogLevel::WARNING);
                     continue;
                 }
             } else {
-                array_push($decoded_events, $event);
+                $decoded_events[] = $event;
             }
         }
-        $webhookobj = new Webhook($decoded_json->time_ms, $decoded_json->events);
-
-        return $webhookobj;
+        return new Webhook($decoded_json->time_ms, $decoded_events);
     }
 
     /**
@@ -810,13 +889,13 @@ public function webhook($headers, $body) : object
      * @param array  $headers an array of headers from the request (for example, from getallheaders())
      * @param string $body    the body of the request (for example, from file_get_contents('php://input'))
      *
-     * @throws PusherException if signature is inccorrect.
+     * @throws PusherException if signature is incorrect.
      */
-    public function ensure_valid_signature($headers, $body)
+    public function verifySignature(array $headers, string $body): void
     {
         $x_pusher_key = $headers['X-Pusher-Key'];
         $x_pusher_signature = $headers['X-Pusher-Signature'];
-        if ($x_pusher_key == $this->settings['auth_key']) {
+        if ($x_pusher_key === $this->settings['auth_key']) {
             $expected = hash_hmac('sha256', $body, $this->settings['secret']);
             if ($expected === $x_pusher_signature) {
                 return;
@@ -825,4 +904,12 @@ public function ensure_valid_signature($headers, $body)
 
         throw new PusherException(sprintf('Received WebHook with invalid signature: got %s.', $x_pusher_signature));
     }
+
+    /**
+     * @deprecated in favour of verifySignature
+     */
+    public function ensure_valid_signature(array $headers, string $body): void
+    {
+        $this->verifySignature($headers, $body);
+    }
 }
diff --git a/src/PusherCrypto.php b/src/PusherCrypto.php
--- a/src/PusherCrypto.php
+++ b/src/PusherCrypto.php
@@ -4,10 +4,10 @@
 
 class PusherCrypto
 {
-    private $encryption_master_key = '';
+    private $encryption_master_key;
 
     // The prefix any e2e channel must have
-    const ENCRYPTED_PREFIX = 'private-encrypted-';
+    public const ENCRYPTED_PREFIX = 'private-encrypted-';
 
     /**
      * Checks if a given channel is an encrypted channel.
@@ -16,24 +16,29 @@ class PusherCrypto
      *
      * @return bool true if channel is an encrypted channel
      */
-    public static function is_encrypted_channel($channel)
+    public static function is_encrypted_channel(string $channel): bool
     {
-        return substr($channel, 0, strlen(self::ENCRYPTED_PREFIX)) === self::ENCRYPTED_PREFIX;
+        return strpos($channel, self::ENCRYPTED_PREFIX) === 0;
     }
 
-    public static function parse_master_key($encryption_master_key_base64)
+    /**
+     * @param $encryption_master_key_base64
+     * @return string
+     * @throws PusherException
+     */
+    public static function parse_master_key($encryption_master_key_base64): string
     {
         if (!function_exists('sodium_crypto_secretbox')) {
             throw new PusherException('To use end to end encryption, you must either be using PHP 7.2 or greater or have installed the libsodium-php extension for php < 7.2.');
         }
 
-        if ($encryption_master_key_base64 != '') {
+        if ($encryption_master_key_base64 !== '') {
             $decoded_key = base64_decode($encryption_master_key_base64, true);
             if ($decoded_key === false) {
                 throw new PusherException('encryption_master_key_base64 must be a valid base64 string');
             }
 
-            if (strlen($decoded_key) != SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
+            if (strlen($decoded_key) !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
                 throw new PusherException('encryption_master_key_base64 must encode a key which is 32 bytes long');
             }
 
@@ -48,7 +53,7 @@ public static function parse_master_key($encryption_master_key_base64)
      *
      * @param string $encryption_master_key the SECRET_KEY_LENGTH key that will be used for key derivation.
      */
-    public function __construct($encryption_master_key)
+    public function __construct(string $encryption_master_key)
     {
         $this->encryption_master_key = $encryption_master_key;
     }
@@ -59,11 +64,12 @@ public function __construct($encryption_master_key)
      * @param object $event an object that has an encrypted data property and a channel property.
      *
      * @return object the event with a decrypted payload, or false if decryption was unsuccessful.
+     * @throws PusherException
      */
-    public function decrypt_event($event)
+    public function decrypt_event(object $event): object
     {
         $parsed_payload = $this->parse_encrypted_message($event->data);
-        $shared_secret = $this->generate_shared_secret($event->channel, $this->encryption_master_key);
+        $shared_secret = $this->generate_shared_secret($event->channel);
         $decrypted_payload = $this->decrypt_payload($parsed_payload->ciphertext, $parsed_payload->nonce, $shared_secret);
         if (!$decrypted_payload) {
             throw new PusherException('Decryption of the payload failed. Wrong key?');
@@ -79,46 +85,54 @@ public function decrypt_event($event)
      * @param string $channel the name of the channel
      *
      * @return string a SHA256 hash (encoded as base64) of the channel name appended to the encryption key
+     * @throws PusherException
      */
-    public function generate_shared_secret($channel)
+    public function generate_shared_secret(string $channel): string
     {
         if (!self::is_encrypted_channel($channel)) {
-            throw new PusherException('You must specify a channel of the form private-encrypted-* for E2E encryption. Got '.$channel);
+            throw new PusherException('You must specify a channel of the form private-encrypted-* for E2E encryption. Got ' . $channel);
         }
 
-        return hash('sha256', $channel.$this->encryption_master_key, true);
+        return hash('sha256', $channel . $this->encryption_master_key, true);
     }
 
     /**
      * Encrypts a given plaintext for broadcast on a particular channel.
      *
-     * @param string $channel   the name of the channel the payloads event will be broadcast on
+     * @param string $channel the name of the channel the payloads event will be broadcast on
      * @param string $plaintext the data to encrypt
      *
      * @return string a string ready to be sent as the data of an event.
+     * @throws PusherException
+     * @throws \SodiumException
      */
-    public function encrypt_payload($channel, $plaintext)
+    public function encrypt_payload(string $channel, string $plaintext): string
     {
         if (!self::is_encrypted_channel($channel)) {
-            throw new PusherException('Cannot encrypt plaintext for a channel that is not of the form private-encrypted-*. Got '.$channel);
+            throw new PusherException('Cannot encrypt plaintext for a channel that is not of the form private-encrypted-*. Got ' . $channel);
         }
         $nonce = $this->generate_nonce();
         $shared_secret = $this->generate_shared_secret($channel);
         $cipher_text = sodium_crypto_secretbox($plaintext, $nonce, $shared_secret);
 
-        return $this->format_encrypted_message($nonce, $cipher_text);
+        try {
+            return $this->format_encrypted_message($nonce, $cipher_text);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data encoding error.');
+        }
     }
 
     /**
      * Decrypts a given payload using the nonce and shared secret.
      *
-     * @param string $payload       the ciphertext
-     * @param string $nonce         the nonce used in the encryption
+     * @param string $payload the ciphertext
+     * @param string $nonce the nonce used in the encryption
      * @param string $shared_secret the shared_secret used in the encryption
      *
      * @return string plaintext
+     * @throws \SodiumException
      */
-    public function decrypt_payload($payload, $nonce, $shared_secret)
+    public function decrypt_payload(string $payload, string $nonce, string $shared_secret)
     {
         $plaintext = sodium_crypto_secretbox_open($payload, $nonce, $shared_secret);
         if (empty($plaintext)) {
@@ -131,18 +145,19 @@ public function decrypt_payload($payload, $nonce, $shared_secret)
     /**
      * Formats an encrypted message ready for broadcast.
      *
-     * @param string $nonce      the nonce used in the encryption process (bytes)
+     * @param string $nonce the nonce used in the encryption process (bytes)
      * @param string $ciphertext the ciphertext (bytes)
      *
      * @return string JSON with base64 encoded nonce and ciphertext`
+     * @throws \JsonException
      */
-    private function format_encrypted_message($nonce, $ciphertext)
+    private function format_encrypted_message(string $nonce, string $ciphertext): string
     {
         $encrypted_message = new \stdClass();
         $encrypted_message->nonce = base64_encode($nonce);
         $encrypted_message->ciphertext = base64_encode($ciphertext);
 
-        return json_encode($encrypted_message);
+        return json_encode($encrypted_message, JSON_THROW_ON_ERROR);
     }
 
     /**
@@ -151,14 +166,20 @@ private function format_encrypted_message($nonce, $ciphertext)
      *
      * @param string $payload the encrypted message payload
      *
-     * @return string php object with decoded nonce and ciphertext
+     * @return object php object with decoded nonce and ciphertext
+     * @throws PusherException
      */
-    private function parse_encrypted_message($payload)
+    private function parse_encrypted_message(string $payload): object
     {
-        $decoded_payload = json_decode($payload);
+        try {
+            $decoded_payload = json_decode($payload, false, 512, JSON_THROW_ON_ERROR);
+        } catch (\JsonException $e) {
+            throw new PusherException('Data decoding error.');
+        }
+
         $decoded_payload->nonce = base64_decode($decoded_payload->nonce);
         $decoded_payload->ciphertext = base64_decode($decoded_payload->ciphertext);
-        if (strlen($decoded_payload->nonce) != SODIUM_CRYPTO_SECRETBOX_NONCEBYTES || $decoded_payload->ciphertext == '') {
+        if ($decoded_payload->ciphertext === '' || strlen($decoded_payload->nonce) !== SODIUM_CRYPTO_SECRETBOX_NONCEBYTES) {
             throw new PusherException('Received a payload that cannot be parsed.');
         }
 
@@ -167,8 +188,10 @@ private function parse_encrypted_message($payload)
 
     /**
      * Generates a nonce that is SODIUM_CRYPTO_SECRETBOX_NONCEBYTES long.
+     * @return string
+     * @throws \Exception
      */
-    private function generate_nonce()
+    private function generate_nonce(): string
     {
         return random_bytes(
             SODIUM_CRYPTO_SECRETBOX_NONCEBYTES
diff --git a/src/PusherInstance.php b/src/PusherInstance.php
--- a/src/PusherInstance.php
+++ b/src/PusherInstance.php
@@ -13,6 +13,7 @@ class PusherInstance
      * Get the pusher singleton instance.
      *
      * @return Pusher
+     * @throws PusherException
      */
     public static function get_pusher()
     {
diff --git a/src/PusherInterface.php b/src/PusherInterface.php
--- a/src/PusherInterface.php
+++ b/src/PusherInterface.php
@@ -1,6 +1,8 @@
 <?php
 
 namespace Pusher;
+
+use GuzzleHttp\Exception\GuzzleException;
 use GuzzleHttp\Promise\PromiseInterface;
 
 interface PusherInterface
@@ -19,7 +21,7 @@ public function getSettings();
      * @param array|string $channels        A channel name or an array of channel names to publish the event on.
      * @param string       $event
      * @param mixed        $data            Event data
-     * @param string|null  $socket_id       [optional]
+     * @param array        $params          [optional]
      * @param bool         $already_encoded [optional]
      *
      * @throws PusherException   Throws exception if $channels is an array of size 101 or above or $socket_id is invalid
@@ -27,23 +29,22 @@ public function getSettings();
      * @throws GuzzleException
      *
      */
-    public function trigger($channels, $event, $data, $socket_id = null, $already_encoded = false) : object;
+    public function trigger($channels, string $event, $data, array $params = [], bool $already_encoded = false): object;
 
     /**
      * Asynchronously trigger an event by providing event name and payload.
      * Optionally provide a socket ID to exclude a client (most likely the sender).
      *
      * @param array|string $channels        A channel name or an array of channel names to publish the event on.
-     * @param string       $event
      * @param mixed        $data            Event data
      * @param array        $params          [optional]
      * @param bool         $already_encoded [optional]
      *
      */
-    public function triggerAsync($channels, $event, $data, $params = array(), $already_encoded = false) : PromiseInterface;
-    
+    public function triggerAsync($channels, string $event, $data, array $params = [], bool $already_encoded = false): PromiseInterface;
+
     /**
-     * 
+     * Trigger multiple events at the same time.
      *
      * @param array $batch           [optional] An array of events to send
      * @param bool  $already_encoded [optional]
@@ -53,10 +54,10 @@ public function triggerAsync($channels, $event, $data, $params = array(), $alrea
      * @throws GuzzleException
      *
      */
-    public function triggerBatch($batch = array(), $already_encoded = false) : object;
+    public function triggerBatch(array $batch = [], bool $already_encoded = false): object;
 
     /**
-     * Trigger multiple events at the same time.
+     * Asynchronously trigger multiple events at the same time.
      *
      * @param array $batch           [optional] An array of events to send
      * @param bool  $already_encoded [optional]
@@ -65,10 +66,10 @@ public function triggerBatch($batch = array(), $already_encoded = false) : objec
      * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
      *
      */
-    public function triggerBatchAsync($batch = array(), $already_encoded = false) : PromiseInterface;
+    public function triggerBatchAsync(array $batch = [], bool $already_encoded = false): PromiseInterface;
 
     /**
-     * Asynchronously trigger multiple events at the same time.
+     * Get information, such as subscriber and user count, for a channel.
      *
      * @param string $channel The name of the channel
      * @param array  $params  Additional parameters for the query e.g. $params = array( 'info' => 'connection_count' )
@@ -78,7 +79,7 @@ public function triggerBatchAsync($batch = array(), $already_encoded = false) :
      * @throws GuzzleException
      *
      */
-    public function get_channel_info($channel, $params = array()) : object;
+    public function getChannelInfo(string $channel, array $params = []): object;
 
     /**
      * Fetch a list containing all channels.
@@ -90,7 +91,7 @@ public function get_channel_info($channel, $params = array()) : object;
      * @throws GuzzleException
      *
      */
-    public function get_channels($params = array()) : object;
+    public function getChannels(array $params = []): object;
 
     /**
      * Fetch user ids currently subscribed to a presence channel.
@@ -102,7 +103,7 @@ public function get_channels($params = array()) : object;
      * @throws GuzzleException
      *
      */
-    public function get_users_info($channel) : object;
+    public function getPresenceUsers(string $channel): object;
 
     /**
      * GET arbitrary REST API resource using a synchronous http client.
@@ -118,33 +119,28 @@ public function get_users_info($channel) : object;
      *
      * @return mixed See Pusher API docs
      */
-    public function get($path, $params = array());
+    public function get(string $path, array $params = [], bool $associative = false);
 
     /**
      * Creates a socket signature.
      *
      * @param string $channel
      * @param string $socket_id
-     * @param string $custom_data
-     *
-     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
-     *
+     * @param string|null $custom_data
      * @return string Json encoded authentication string.
+     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
      */
-    public function socket_auth($channel, $socket_id, $custom_data = null) : string;
+    public function socketAuth(string $channel, string $socket_id, string $custom_data = null): string;
 
     /**
      * Creates a presence signature (an extension of socket signing).
      *
-     * @param string $channel
-     * @param string $socket_id
-     * @param string $user_id
      * @param mixed  $user_info
      *
      * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
      *
      */
-    public function presence_auth($channel, $socket_id, $user_id, $user_info = null) : string;
+    public function presenceAuth(string $channel, string $socket_id, string $user_id, $user_info = null): string;
 
     /**
      * Verify that a webhook actually came from Pusher, decrypts any
@@ -157,15 +153,105 @@ public function presence_auth($channel, $socket_id, $user_id, $user_info = null)
      *
      * @return Webhook marshalled object with the properties time_ms (an int) and events (an array of event objects)
      */
-    public function webhook($headers, $body) : object;
+    public function webhook(array $headers, string $body): object;
+
+    /**
+     * Verify that a given Pusher Signature is valid.
+     *
+     * @param array  $headers an array of headers from the request (for example, from getallheaders())
+     * @param string $body    the body of the request (for example, from file_get_contents('php://input'))
+     *
+     * @throws PusherException if signature is incorrect.
+     */
+    public function verifySignature(array $headers, string $body);
+
+
+    /*******************************************************************
+     *
+     * DEPRECATION WARNING:
+     *
+     * all the functions below have been deprecated in favour of their
+     * camelCased variants. They will be removed in the next major
+     * update.
+     */
+
+    /**
+     * Get information, such as subscriber and user count, for a channel.
+     *
+     * @deprecated in favour of getChannelInfo
+     *
+     * @param string $channel The name of the channel
+     * @param array  $params  Additional parameters for the query e.g. $params = array( 'info' => 'connection_count' )
+     *
+     * @throws PusherException   If $channel is invalid or if curl wasn't initialized correctly
+     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
+     * @throws GuzzleException
+     *
+     */
+    public function get_channel_info(string $channel, array $params = []): object;
+
+    /**
+     * Fetch a list containing all channels.
+     *
+     * @deprecated in favour of getChannels
+     *
+     * @param array $params Additional parameters for the query e.g. $params = array( 'info' => 'connection_count' )
+     *
+     * @throws PusherException   Throws exception if curl wasn't initialized correctly
+     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
+     * @throws GuzzleException
+     *
+     */
+    public function get_channels(array $params = []): object;
+
+    /**
+     * Fetch user ids currently subscribed to a presence channel.
+     *
+     * @deprecated in favour of getPresenceUsers
+     *
+     * @param string $channel The name of the channel
+     *
+     * @throws PusherException   Throws exception if curl wasn't initialized correctly
+     * @throws ApiErrorException Throws ApiErrorException if the Channels HTTP API responds with an error
+     * @throws GuzzleException
+     *
+     */
+    public function get_users_info(string $channel): object;
+
+    /**
+     * Creates a socket signature.
+     *
+     * @deprecated in favour of socketAuth
+     *
+     * @param string $channel
+     * @param string $socket_id
+     * @param string|null $custom_data
+     * @return string Json encoded authentication string.
+     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
+     */
+    public function socket_auth(string $channel, string $socket_id, string $custom_data = null): string;
+
+    /**
+     * Creates a presence signature (an extension of socket signing).
+     *
+     * @deprecated in favour of presenceAuth
+     *
+     * @param mixed  $user_info
+     *
+     * @throws PusherException Throws exception if $channel is invalid or above or $socket_id is invalid
+     *
+     */
+    public function presence_auth(string $channel, string $socket_id, string $user_id, $user_info = null): string;
 
     /**
      * Verify that a given Pusher Signature is valid.
      *
+     * @deprecated in favour of verifySignature
+     *
      * @param array  $headers an array of headers from the request (for example, from getallheaders())
      * @param string $body    the body of the request (for example, from file_get_contents('php://input'))
      *
-     * @throws PusherException if signature is inccorrect.
+     * @throws PusherException if signature is incorrect.
      */
-    public function ensure_valid_signature($headers, $body);
+    public function ensure_valid_signature(array $headers, string $body);
 }
diff --git a/src/Webhook.php b/src/Webhook.php
--- a/src/Webhook.php
+++ b/src/Webhook.php
@@ -4,8 +4,10 @@
 
 class Webhook
 {
+    /** @var int $time_ms */
     private $time_ms;
-    private $events = array();
+    /** @var array $events */
+    private $events;
 
     public function __construct($time_ms, $events)
     {
@@ -13,12 +15,12 @@ public function __construct($time_ms, $events)
         $this->events = $events;
     }
 
-    public function get_events()
+    public function get_events(): array
     {
         return $this->events;
     }
 
-    public function get_time_ms()
+    public function get_time_ms(): int
     {
         return $this->time_ms;
     }


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        php: [7.2, 7.3, 7.4, 8.0]
+        php: [7.3, 7.4, 8.0]
         stability: [prefer-lowest, prefer-stable]
 
     name: PHP ${{ matrix.php }} - ${{ matrix.stability }} Test
@@ -42,5 +42,5 @@ jobs:
           PUSHERAPP_APPID: ${{ secrets.CI_APP_ID }}
           PUSHERAPP_AUTHKEY: ${{ secrets.CI_APP_KEY }}
           PUSHERAPP_SECRET: ${{ secrets.CI_APP_SECRET }}
-          PUSHERAPP_HOST: http://api-${{ secrets.CI_APP_CLUSTER }}.pusher.com
+          PUSHERAPP_CLUSTER: ${{ secrets.CI_APP_CLUSTER }}
         run: composer exec phpunit tests/acceptance
diff --git a/tests/acceptance/ChannelQueryTest.php b/tests/acceptance/ChannelQueryTest.php
--- a/tests/acceptance/ChannelQueryTest.php
+++ b/tests/acceptance/ChannelQueryTest.php
@@ -1,100 +1,119 @@
 <?php
 
-class ChannelQueryTest extends PHPUnit\Framework\TestCase
+namespace acceptance;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+
+class ChannelQueryTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
-        $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST]);
+        if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
+            self::markTestSkipped('Please set the
+            PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
+            PUSHERAPP_APPID keys.');
+        } else {
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER]);
+        }
     }
 
-    public function testChannelInfo()
+    public function testChannelInfo(): void
     {
         $result = $this->pusher->get_channel_info('channel-test');
 
-        $this->assertObjectHasAttribute('occupied', $result, 'class has occupied attribute');
+        self::assertObjectHasAttribute('occupied', $result, 'class has occupied attribute');
     }
 
-    public function testChannelList()
+    public function testChannelList(): void
     {
         $result = $this->pusher->get_channels();
         $channels = $result->channels;
 
-        $this->assertTrue(is_array($channels), 'channels is an array');
+        self::assertIsArray($channels, 'channels is an array');
     }
 
-    public function testFilterByPrefixNoChannels()
+    public function testFilterByPrefixNoChannels(): void
     {
-        $options = array(
+        $options = [
             'filter_by_prefix' => '__fish',
-        );
+        ];
         $result = $this->pusher->get_channels($options);
 
         $channels = $result->channels;
 
-        $this->assertTrue(is_array($channels), 'channels is an array');
-        $this->assertEquals(0, count($channels), 'should be an empty array');
+        self::assertIsArray($channels, 'channels is an array');
+        self::assertCount(0, $channels, 'should be an empty array');
     }
 
-    public function testFilterByPrefixOneChannel()
+    public function testFilterByPrefixOneChannel(): void
     {
-        $options = array(
+        $options = [
             'filter_by_prefix' => 'my-',
-        );
+        ];
         $result = $this->pusher->get_channels($options);
 
         $channels = $result->channels;
 
-        $this->assertEquals(1, count($channels), 'channels have a single test-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
+        $this->assertCount(1, $channels,
+            'channels have a single test-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
     }
 
-    public function testUsersInfo()
+    public function testUsersInfo(): void
     {
         $result = $this->pusher->get_users_info('presence-channel-test');
 
         $this->assertObjectHasAttribute('users', $result, 'class has users attribute');
     }
 
-    public function testProvidingInfoParameterWithPrefixQueryFailsForPublicChannel()
+    public function testProvidingInfoParameterWithPrefixQueryFailsForPublicChannel(): void
     {
         $this->expectException(\Pusher\ApiErrorException::class);
 
-        $options = array(
+        $options = [
             'filter_by_prefix' => 'test_',
             'info'             => 'user_count',
-        );
+        ];
         $result = $this->pusher->get_channels($options);
     }
 
-    public function testChannelListUsingGenericGet()
+    public function testChannelListUsingGenericGet(): void
     {
-        $result = $this->pusher->get('/channels', array(), true);
+        $result = $this->pusher->get('/channels', [], true);
 
         $channels = $result['channels'];
 
-        $this->assertEquals(1, count($channels), 'channels have a single my-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
+        self::assertCount(1, $channels,
+            'channels have a single my-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
 
         $my_channel = $channels['my-channel'];
 
-        $this->assertEquals(0, count($my_channel));
+        self::assertCount(0, $my_channel);
     }
 
-    public function testChannelListUsingGenericGetAndPrefixParam()
+    public function testChannelListUsingGenericGetAndPrefixParam(): void
     {
-        $result = $this->pusher->get('/channels', array('filter_by_prefix' => 'my-'), true);
+        $result = $this->pusher->get('/channels', ['filter_by_prefix' => 'my-'], true);
 
         $channels = $result['channels'];
 
-        $this->assertEquals(1, count($channels), 'channels have a single my-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
+        self::assertCount(1, $channels,
+            'channels have a single my-channel present. For this test to pass you must have the "Getting Started" page open on the dashboard for the app you are testing against');
 
         $my_channel = $channels['my-channel'];
 
-        $this->assertEquals(0, count($my_channel));
+        self::assertCount(0, $my_channel);
     }
 
-    public function testSingleChannelInfoUsingGenericGet()
+    public function testSingleChannelInfoUsingGenericGet(): void
     {
         $result = $this->pusher->get('/channels/channel-test');
 
-        $this->assertObjectHasAttribute('occupied', $result, 'class has occupied attribute');
+        self::assertObjectHasAttribute('occupied', $result, 'class has occupied attribute');
     }
 }
diff --git a/tests/acceptance/MiddlewareTest.php b/tests/acceptance/MiddlewareTest.php
--- a/tests/acceptance/MiddlewareTest.php
+++ b/tests/acceptance/MiddlewareTest.php
@@ -1,14 +1,24 @@
 <?php
 
+namespace acceptance;
+
+use Closure;
 use GuzzleHttp\Client;
 use GuzzleHttp\HandlerStack;
 use GuzzleHttp\Handler\CurlHandler;
+use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\RequestInterface;
+use Pusher\Pusher;
 
-class MiddlewareTest extends PHPUnit\Framework\TestCase
+class MiddlewareTest extends TestCase
 {
     private $count = 0;
-    function increment()
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
+    public function increment(): Closure
     {
         return function (callable $handler) {
             return function (RequestInterface $request, array $options) use ($handler) {
@@ -21,7 +31,7 @@ function increment()
     protected function setUp(): void
     {
         if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
-            $this->markTestSkipped('Please set the
+            self::markTestSkipped('Please set the
             PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
             PUSHERAPP_APPID keys.');
         } else {
@@ -29,14 +39,14 @@ protected function setUp(): void
             $stack->setHandler(new CurlHandler());
             $stack->push($this->increment());
             $client = new Client(['handler' => $stack]);
-            $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST], $client);
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER], $client);
         }
     }
 
-    public function testStringPush()
+    public function testStringPush(): void
     {
-        $this->assertEquals(0, $this->count);
+        self::assertEquals(0, $this->count);
         $result = $this->pusher->trigger('test_channel', 'my_event', 'Test string');
-        $this->assertEquals(1, $this->count);
+        self::assertEquals(1, $this->count);
     }
 }
diff --git a/tests/acceptance/TriggerAsyncTest.php b/tests/acceptance/TriggerAsyncTest.php
--- a/tests/acceptance/TriggerAsyncTest.php
+++ b/tests/acceptance/TriggerAsyncTest.php
@@ -1,42 +1,53 @@
 <?php
 
-class TriggerAsyncTest extends PHPUnit\Framework\TestCase
+namespace acceptance;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+use stdClass;
+
+class TriggerAsyncTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
         if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
-            $this->markTestSkipped('Please set the
+            self::markTestSkipped('Please set the
             PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
             PUSHERAPP_APPID keys.');
         } else {
-            $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST]);
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER]);
         }
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->pusher, 'Created new Pusher\Pusher object');
+        self::assertNotNull($this->pusher, 'Created new \Pusher\Pusher object');
     }
 
-    public function testStringPush()
+    public function testStringPush(): void
     {
         $result = $this->pusher->triggerAsync('test_channel', 'my_event', 'Test string')->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testArrayPush()
+    public function testArrayPush(): void
     {
-        $result = $this->pusher->triggerAsync('test_channel', 'my_event', array('test' => 1))->wait();
-        $this->assertEquals(new stdClass(), $result);
+        $result = $this->pusher->triggerAsync('test_channel', 'my_event', ['test' => 1])->wait();
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testPushWithSocketId()
+    public function testPushWithSocketId(): void
     {
-        $result = $this->pusher->triggerAsync('test_channel', 'my_event', array('test' => 1), array('socket_id' => '123.456'))->wait();
-        $this->assertEquals(new stdClass(), $result);
+        $result = $this->pusher->triggerAsync('test_channel', 'my_event', ['test' => 1], ['socket_id' => '123.456'])->wait();
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testPushWithInfo()
+    public function testPushWithInfo(): void
     {
         $expectedMyChannel = new stdClass();
         $expectedMyChannel->subscription_count = 1;
@@ -44,78 +55,78 @@ public function testPushWithInfo()
         $expectedPresenceMyChannel->user_count = 0;
         $expectedPresenceMyChannel->subscription_count = 0;
         $expectedResult = new stdClass();
-        $expectedResult->channels = array(
+        $expectedResult->channels = [
             "my-channel" => $expectedMyChannel,
             "presence-my-channel" => $expectedPresenceMyChannel,
-        );
+        ];
 
-        $result = $this->pusher->triggerAsync(['my-channel', 'presence-my-channel'], 'my_event', array('test' => 1), array('info' => 'user_count,subscription_count'))->wait();
-        $this->assertEquals($expectedResult, $result);
+        $result = $this->pusher->triggerAsync(['my-channel', 'presence-my-channel'], 'my_event', ['test' => 1], ['info' => 'user_count,subscription_count'])->wait();
+        self::assertEquals($expectedResult, $result);
     }
 
-    public function testTLSPush()
+    public function testTLSPush(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $result = $pusher->triggerAsync('test_channel', 'my_event', array('encrypted' => 1))->wait();
-        $this->assertEquals(new stdClass(), $result);
+        $result = $pusher->triggerAsync('test_channel', 'my_event', ['encrypted' => 1])->wait();
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testSendingOver10kBMessageReturns413()
+    public function testSendingOver10kBMessageReturns413(): void
     {
         $this->expectException(\Pusher\ApiErrorException::class);
         $this->expectExceptionCode('413');
 
         $data = str_pad('', 11 * 1024, 'a');
-        $this->pusher->triggerAsync('test_channel', 'my_event', $data, array(), true)->wait();
+        $this->pusher->triggerAsync('test_channel', 'my_event', $data, [], true)->wait();
     }
 
-    public function testTriggeringEventOnOver100ChannelsThrowsException()
+    public function testTriggeringEventOnOver100ChannelsThrowsException(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
-        $channels = array();
+        $channels = [];
         while (count($channels) <= 101) {
-            $channels[] = ('channel-'.count($channels));
+            $channels[] = ('channel-' . count($channels));
         }
-        $data = array('event_name' => 'event_data');
+        $data = ['event_name' => 'event_data'];
         $this->pusher->triggerAsync($channels, 'my_event', $data)->wait();
     }
 
-    public function testTriggeringEventOnMultipleChannels()
+    public function testTriggeringEventOnMultipleChannels(): void
     {
-        $data = array('event_name' => 'event_data');
-        $channels = array('test_channel_1', 'test_channel_2');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['test_channel_1', 'test_channel_2'];
         $result = $this->pusher->triggerAsync($channels, 'my_event', $data)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggeringEventOnPrivateEncryptedChannelSuccess()
+    public function testTriggeringEventOnPrivateEncryptedChannelSuccess(): void
     {
         $options = ['encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-                    'host' => PUSHERAPP_HOST];
-        $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+                    'cluster' => PUSHERAPP_CLUSTER];
+        $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $data = array('event_name' => 'event_data');
-        $channels = array('private-encrypted-ceppaio');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['private-encrypted-ceppaio'];
         $result = $this->pusher->triggerAsync($channels, 'my_event', $data)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggeringEventOnMultipleChannelsWithEncryptedChannelPresentError()
+    public function testTriggeringEventOnMultipleChannelsWithEncryptedChannelPresentError(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $options = ['encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-                    'host' => PUSHERAPP_HOST];
-        $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+                    'cluster' => PUSHERAPP_CLUSTER];
+        $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $data = array('event_name' => 'event_data');
-        $channels = array('my-chan-ceppaio', 'private-encrypted-ceppaio');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['my-chan-ceppaio', 'private-encrypted-ceppaio'];
         $this->pusher->triggerAsync($channels, 'my_event', $data)->wait();
     }
 }
diff --git a/tests/acceptance/TriggerBatchAsyncTest.php b/tests/acceptance/TriggerBatchAsyncTest.php
--- a/tests/acceptance/TriggerBatchAsyncTest.php
+++ b/tests/acceptance/TriggerBatchAsyncTest.php
@@ -1,7 +1,19 @@
 <?php
 
-class TriggerBatchAsyncTest extends PHPUnit\Framework\TestCase
+namespace acceptance;
+
+use Error;
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+use stdClass;
+
+class TriggerBatchAsyncTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
         if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
@@ -9,73 +21,73 @@ protected function setUp(): void
             PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
             PUSHERAPP_APPID keys.');
         } else {
-            $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST]);
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER]);
         }
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->pusher, 'Created new Pusher\Pusher object');
+        self::assertNotNull($this->pusher, 'Created new \Pusher\Pusher object');
     }
 
-    public function testSimplePush()
+    public function testSimplePush(): void
     {
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
         $result = $this->pusher->triggerBatchAsync($batch)->wait();
         $this->assertEquals(new stdClass(), $result);
     }
 
-    public function testTLSPush()
+    public function testTLSPush(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchNonEncryptedEventsWithObjectPayloads()
+    public function testTriggerBatchNonEncryptedEventsWithObjectPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'mio_canale', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'mio_canale', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithSingleEvent()
+    public function testTriggerBatchWithSingleEvent(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithInfo()
+    public function testTriggerBatchWithInfo(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
         $expectedMyChannel = new stdClass();
         $expectedMyChannel->subscription_count = 1;
@@ -84,150 +96,150 @@ public function testTriggerBatchWithInfo()
         $expectedPresenceMyChannel->user_count = 0;
         $expectedPresenceMyChannel->subscription_count = 0;
         $expectedResult = new stdClass();
-        $expectedResult->batch = array(
+        $expectedResult->batch = [
             $expectedMyChannel,
             $expectedMyChannel2,
             $expectedPresenceMyChannel
-        );
+        ];
 
-        $batch = array();
-        $batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'subscription_count');
-        $batch[] = array('channel' => 'my-channel-2', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'user_count,subscription_count');
+        $batch = [];
+        $batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'subscription_count'];
+        $batch[] = ['channel' => 'my-channel-2', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'user_count,subscription_count'];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals($expectedResult, $result);
+        self::assertEquals($expectedResult, $result);
     }
 
-    public function testTriggerBatchWithMultipleNonEncryptedEventsWithStringPayloads()
+    public function testTriggerBatchWithMultipleNonEncryptedEventsWithStringPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'test_channel2', 'name' => 'my_event2', 'data' => 'test-string2');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'test_channel2', 'name' => 'my_event2', 'data' => 'test-string2'];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleCombinationsofStringAndObjectPayloads()
+    public function testTriggerBatchWithMultipleCombinationsofStringAndObjectPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'test_channel2', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'test_channel2', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithWithEncryptedEventSuccess()
+    public function testTriggerBatchWithWithEncryptedEventSuccess(): void
     {
-        $options = array(
-            'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+        $options = [
+            'useTLS'  => true,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'private-encrypted-test_channel', 'name' => 'my_event', 'data' => 'test-string');
+        $batch = [];
+        $batch[] = ['channel' => 'private-encrypted-test_channel', 'name' => 'my_event', 'data' => 'test-string'];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleEncryptedEventsSuccess()
+    public function testTriggerBatchWithMultipleEncryptedEventsSuccess(): void
     {
-        $options = array(
-            'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+        $options = [
+            'useTLS' => true,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => 'test-string2');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => 'test-string2'];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleCombinationsofStringsAndObjectsWithEncryptedEventSuccess()
+    public function testTriggerBatchWithMultipleCombinationsofStringsAndObjectsWithEncryptedEventSuccess(): void
     {
-        $options = array(
-            'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+        $options = [
+            'useTLS' => true,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'secret-string');
-        $batch[] = array('channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'secret-string'];
+        $batch[] = ['channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchMultipleEventsWithEncryptedEventWithoutEncryptionMasterKeyError()
+    public function testTriggerBatchMultipleEventsWithEncryptedEventWithoutEncryptionMasterKeyError(): void
     {
         $this->expectException(Error::class);
 
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'my_test_chan', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => array('my' => 'to_be_encrypted_data_shhhht'));
+        $batch = [];
+        $batch[] = ['channel' => 'my_test_chan', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => ['my' => 'to_be_encrypted_data_shhhht']];
         $pc->triggerBatchAsync($batch)->wait();
     }
 
-    public function testTriggerBatchWithMultipleEncryptedEventsWithEncryptionMasterKeySuccess()
+    public function testTriggerBatchWithMultipleEncryptedEventsWithEncryptionMasterKeySuccess(): void
     {
-        $options = array(
+        $options = [
             'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'my_test_chan', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => array('my' => 'to_be_encrypted_data_shhhht'));
+        $batch = [];
+        $batch[] = ['channel' => 'my_test_chan', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => ['my' => 'to_be_encrypted_data_shhhht']];
         $result = $pc->triggerBatchAsync($batch)->wait();
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testSendingOver10kBMessageReturns413()
+    public function testSendingOver10kBMessageReturns413(): void
     {
         $this->expectException(\Pusher\ApiErrorException::class);
         $this->expectExceptionMessage('content of this event');
         $this->expectExceptionCode('413');
 
         $data = str_pad('', 11 * 1024, 'a');
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => $data);
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => $data];
         $this->pusher->triggerBatchAsync($batch, true)->wait();
     }
 
-    public function testSendingOver10messagesReturns400()
+    public function testSendingOver10messagesReturns400(): void
     {
         $this->expectException(\Pusher\ApiErrorException::class);
         $this->expectExceptionMessage('Batch too large');
         $this->expectExceptionCode('400');
 
-        $batch = array();
+        $batch = [];
         foreach (range(1, 11) as $i) {
-            $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('index' => $i));
+            $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['index' => $i]];
         }
         $this->pusher->triggerBatchAsync($batch, false)->wait();
     }
diff --git a/tests/acceptance/TriggerBatchTest.php b/tests/acceptance/TriggerBatchTest.php
--- a/tests/acceptance/TriggerBatchTest.php
+++ b/tests/acceptance/TriggerBatchTest.php
@@ -1,7 +1,20 @@
 <?php
 
-class TriggerBatchTest extends PHPUnit\Framework\TestCase
+namespace acceptance;
+
+use Error;
+use PHPUnit\Framework\TestCase;
+use Pusher\ApiErrorException;
+use Pusher\Pusher;
+use stdClass;
+
+class TriggerBatchTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
         if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
@@ -9,73 +22,73 @@ protected function setUp(): void
             PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
             PUSHERAPP_APPID keys.');
         } else {
-            $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST]);
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER]);
         }
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->pusher, 'Created new Pusher\Pusher object');
+        self::assertNotNull($this->pusher, 'Created new \Pusher\Pusher object');
     }
 
-    public function testSimplePush()
+    public function testSimplePush(): void
     {
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
         $result = $this->pusher->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTLSPush()
+    public function testTLSPush(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchNonEncryptedEventsWithObjectPayloads()
+    public function testTriggerBatchNonEncryptedEventsWithObjectPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'mio_canale', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'mio_canale', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithSingleEvent()
+    public function testTriggerBatchWithSingleEvent(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
         $result = $pc->triggerBatch($batch);
         $this->assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithInfo()
+    public function testTriggerBatchWithInfo(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
         $expectedMyChannel = new stdClass();
         $expectedMyChannel->subscription_count = 1;
@@ -84,150 +97,150 @@ public function testTriggerBatchWithInfo()
         $expectedPresenceMyChannel->user_count = 0;
         $expectedPresenceMyChannel->subscription_count = 0;
         $expectedResult = new stdClass();
-        $expectedResult->batch = array(
+        $expectedResult->batch = [
             $expectedMyChannel,
             $expectedMyChannel2,
             $expectedPresenceMyChannel
-        );
+        ];
 
-        $batch = array();
-        $batch[] = array('channel' => 'my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'subscription_count');
-        $batch[] = array('channel' => 'my-channel-2', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'user_count,subscription_count');
+        $batch = [];
+        $batch[] = ['channel' => 'my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'subscription_count'];
+        $batch[] = ['channel' => 'my-channel-2', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'presence-my-channel', 'name' => 'my_event', 'data' => 'test-string', 'info' => 'user_count,subscription_count'];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals($expectedResult, $result);
+        self::assertEquals($expectedResult, $result);
     }
 
-    public function testTriggerBatchWithMultipleNonEncryptedEventsWithStringPayloads()
+    public function testTriggerBatchWithMultipleNonEncryptedEventsWithStringPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'test_channel2', 'name' => 'my_event2', 'data' => 'test-string2');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'test_channel2', 'name' => 'my_event2', 'data' => 'test-string2'];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleCombinationsofStringAndObjectPayloads()
+    public function testTriggerBatchWithMultipleCombinationsofStringAndObjectPayloads(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'test_channel2', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'test_channel2', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithWithEncryptedEventSuccess()
+    public function testTriggerBatchWithWithEncryptedEventSuccess(): void
     {
-        $options = array(
+        $options = [
             'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'private-encrypted-test_channel', 'name' => 'my_event', 'data' => 'test-string');
+        $batch = [];
+        $batch[] = ['channel' => 'private-encrypted-test_channel', 'name' => 'my_event', 'data' => 'test-string'];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleEncryptedEventsSuccess()
+    public function testTriggerBatchWithMultipleEncryptedEventsSuccess(): void
     {
-        $options = array(
+        $options = [
             'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string');
-        $batch[] = array('channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => 'test-string2');
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'test-string'];
+        $batch[] = ['channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => 'test-string2'];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchWithMultipleCombinationsofStringsAndObjectsWithEncryptedEventSuccess()
+    public function testTriggerBatchWithMultipleCombinationsofStringsAndObjectsWithEncryptedEventSuccess(): void
     {
-        $options = array(
+        $options = [
             'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => 'secret-string');
-        $batch[] = array('channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => array('my' => 'data2'));
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => 'secret-string'];
+        $batch[] = ['channel' => 'private-encrypted-test_channel2', 'name' => 'my_event2', 'data' => ['my' => 'data2']];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggerBatchMultipleEventsWithEncryptedEventWithoutEncryptionMasterKeyError()
+    public function testTriggerBatchMultipleEventsWithEncryptedEventWithoutEncryptionMasterKeyError(): void
     {
         $this->expectException(Error::class);
 
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'my_test_chan', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => array('my' => 'to_be_encrypted_data_shhhht'));
+        $batch = [];
+        $batch[] = ['channel' => 'my_test_chan', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => ['my' => 'to_be_encrypted_data_shhhht']];
         $pc->triggerBatch($batch);
     }
 
-    public function testTriggerBatchWithMultipleEncryptedEventsWithEncryptionMasterKeySuccess()
+    public function testTriggerBatchWithMultipleEncryptedEventsWithEncryptionMasterKeySuccess(): void
     {
-        $options = array(
-            'useTLS'                       => true,
-            'host'                         => PUSHERAPP_HOST,
+        $options = [
+            'useTLS' => true,
+            'cluster' => PUSHERAPP_CLUSTER,
             'encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-        );
-        $pc = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+        ];
+        $pc = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $batch = array();
-        $batch[] = array('channel' => 'my_test_chan', 'name' => 'my_event', 'data' => array('my' => 'data'));
-        $batch[] = array('channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => array('my' => 'to_be_encrypted_data_shhhht'));
+        $batch = [];
+        $batch[] = ['channel' => 'my_test_chan', 'name' => 'my_event', 'data' => ['my' => 'data']];
+        $batch[] = ['channel' => 'private-encrypted-ceppaio', 'name' => 'my_private_encrypted_event', 'data' => ['my' => 'to_be_encrypted_data_shhhht']];
         $result = $pc->triggerBatch($batch);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testSendingOver10kBMessageReturns413()
+    public function testSendingOver10kBMessageReturns413(): void
     {
-        $this->expectException(\Pusher\ApiErrorException::class);
+        $this->expectException(ApiErrorException::class);
         $this->expectExceptionMessage('content of this event');
         $this->expectExceptionCode('413');
 
         $data = str_pad('', 11 * 1024, 'a');
-        $batch = array();
-        $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => $data);
+        $batch = [];
+        $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => $data];
         $this->pusher->triggerBatch($batch, true);
     }
 
-    public function testSendingOver10messagesReturns400()
+    public function testSendingOver10messagesReturns400(): void
     {
-        $this->expectException(\Pusher\ApiErrorException::class);
+        $this->expectException(ApiErrorException::class);
         $this->expectExceptionMessage('Batch too large');
         $this->expectExceptionCode('400');
 
-        $batch = array();
+        $batch = [];
         foreach (range(1, 11) as $i) {
-            $batch[] = array('channel' => 'test_channel', 'name' => 'my_event', 'data' => array('index' => $i));
+            $batch[] = ['channel' => 'test_channel', 'name' => 'my_event', 'data' => ['index' => $i]];
         }
         $this->pusher->triggerBatch($batch, false);
     }
diff --git a/tests/acceptance/TriggerTest.php b/tests/acceptance/TriggerTest.php
--- a/tests/acceptance/TriggerTest.php
+++ b/tests/acceptance/TriggerTest.php
@@ -1,42 +1,55 @@
 <?php
 
-class TriggerTest extends PHPUnit\Framework\TestCase
+namespace acceptance;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\ApiErrorException;
+use Pusher\Pusher;
+use Pusher\PusherException;
+use stdClass;
+
+class TriggerTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
         if (PUSHERAPP_AUTHKEY === '' || PUSHERAPP_SECRET === '' || PUSHERAPP_APPID === '') {
-            $this->markTestSkipped('Please set the
+            self::markTestSkipped('Please set the
             PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
             PUSHERAPP_APPID keys.');
         } else {
-            $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['host' => PUSHERAPP_HOST]);
+            $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, ['cluster' => PUSHERAPP_CLUSTER]);
         }
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->pusher, 'Created new Pusher\Pusher object');
+        self::assertNotNull($this->pusher, 'Created new \Pusher\Pusher object');
     }
 
-    public function testStringPush()
+    public function testStringPush(): void
     {
         $result = $this->pusher->trigger('test_channel', 'my_event', 'Test string');
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testArrayPush()
+    public function testArrayPush(): void
     {
-        $result = $this->pusher->trigger('test_channel', 'my_event', array('test' => 1));
-        $this->assertEquals(new stdClass(), $result);
+        $result = $this->pusher->trigger('test_channel', 'my_event', ['test' => 1]);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testPushWithSocketId()
+    public function testPushWithSocketId(): void
     {
-        $result = $this->pusher->trigger('test_channel', 'my_event', array('test' => 1), array('socket_id' => '123.456'));
-        $this->assertEquals(new stdClass(), $result);
+        $result = $this->pusher->trigger('test_channel', 'my_event', ['test' => 1], ['socket_id' => '123.456']);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testPushWithInfo()
+    public function testPushWithInfo(): void
     {
         $expectedMyChannel = new stdClass();
         $expectedMyChannel->subscription_count = 1;
@@ -44,78 +57,78 @@ public function testPushWithInfo()
         $expectedPresenceMyChannel->user_count = 0;
         $expectedPresenceMyChannel->subscription_count = 0;
         $expectedResult = new stdClass();
-        $expectedResult->channels = array(
+        $expectedResult->channels = [
             "my-channel" => $expectedMyChannel,
             "presence-my-channel" => $expectedPresenceMyChannel,
-        );
+        ];
 
-        $result = $this->pusher->trigger(['my-channel', 'presence-my-channel'], 'my_event', array('test' => 1), array('info' => 'user_count,subscription_count'));
-        $this->assertEquals($expectedResult, $result);
+        $result = $this->pusher->trigger(['my-channel', 'presence-my-channel'], 'my_event', ['test' => 1], ['info' => 'user_count,subscription_count']);
+        self::assertEquals($expectedResult, $result);
     }
 
-    public function testTLSPush()
+    public function testTLSPush(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
-            'host'   => PUSHERAPP_HOST,
-        );
-        $pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+            'cluster' => PUSHERAPP_CLUSTER,
+        ];
+        $pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $result = $pusher->trigger('test_channel', 'my_event', array('encrypted' => 1));
-        $this->assertEquals(new stdClass(), $result);
+        $result = $pusher->trigger('test_channel', 'my_event', ['encrypted' => 1]);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testSendingOver10kBMessageReturns413()
+    public function testSendingOver10kBMessageReturns413(): void
     {
-        $this->expectException(\Pusher\ApiErrorException::class);
+        $this->expectException(ApiErrorException::class);
         $this->expectExceptionCode('413');
 
         $data = str_pad('', 11 * 1024, 'a');
-        $this->pusher->trigger('test_channel', 'my_event', $data, array(), true);
+        $this->pusher->trigger('test_channel', 'my_event', $data, [], true);
     }
 
-    public function testTriggeringEventOnOver100ChannelsThrowsException()
+    public function testTriggeringEventOnOver100ChannelsThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $channels = array();
+        $channels = [];
         while (count($channels) <= 101) {
-            $channels[] = ('channel-'.count($channels));
+            $channels[] = ('channel-' . count($channels));
         }
-        $data = array('event_name' => 'event_data');
+        $data = ['event_name' => 'event_data'];
         $this->pusher->trigger($channels, 'my_event', $data);
     }
 
-    public function testTriggeringEventOnMultipleChannels()
+    public function testTriggeringEventOnMultipleChannels(): void
     {
-        $data = array('event_name' => 'event_data');
-        $channels = array('test_channel_1', 'test_channel_2');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['test_channel_1', 'test_channel_2'];
         $result = $this->pusher->trigger($channels, 'my_event', $data);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggeringEventOnPrivateEncryptedChannelSuccess()
+    public function testTriggeringEventOnPrivateEncryptedChannelSuccess(): void
     {
         $options = ['encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-                    'host' => PUSHERAPP_HOST];
-        $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+                    'cluster' => PUSHERAPP_CLUSTER];
+        $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $data = array('event_name' => 'event_data');
-        $channels = array('private-encrypted-ceppaio');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['private-encrypted-ceppaio'];
         $result = $this->pusher->trigger($channels, 'my_event', $data);
-        $this->assertEquals(new stdClass(), $result);
+        self::assertEquals(new stdClass(), $result);
     }
 
-    public function testTriggeringEventOnMultipleChannelsWithEncryptedChannelPresentError()
+    public function testTriggeringEventOnMultipleChannelsWithEncryptedChannelPresentError(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $options = ['encryption_master_key_base64' => 'Y0F6UkgzVzlGWk0zaVhxU05JR3RLenR3TnVDejl4TVY=',
-                    'host' => PUSHERAPP_HOST];
-        $this->pusher = new Pusher\Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
+                    'cluster' => PUSHERAPP_CLUSTER];
+        $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, $options);
 
-        $data = array('event_name' => 'event_data');
-        $channels = array('my-chan-ceppaio', 'private-encrypted-ceppaio');
+        $data = ['event_name' => 'event_data'];
+        $channels = ['my-chan-ceppaio', 'private-encrypted-ceppaio'];
         $this->pusher->trigger($channels, 'my_event', $data);
     }
 }
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -2,14 +2,12 @@
 
 error_reporting(E_ALL);
 
-$dir = dirname(__FILE__);
-$config_path = $dir.'/config.php';
-if (file_exists($config_path) === true) {
-    require_once $config_path;
+if (file_exists(__DIR__ . '/config.php') === true) {
+    require 'config.php';
 } else {
     define('PUSHERAPP_AUTHKEY', getenv('PUSHERAPP_AUTHKEY'));
     define('PUSHERAPP_SECRET', getenv('PUSHERAPP_SECRET'));
     define('PUSHERAPP_APPID', getenv('PUSHERAPP_APPID'));
 
-    define('PUSHERAPP_HOST', getenv('PUSHERAPP_HOST'));
+    define('PUSHERAPP_CLUSTER', getenv('PUSHERAPP_CLUSTER'));
 }
diff --git a/tests/config.example.php b/tests/config.example.php
--- a/tests/config.example.php
+++ b/tests/config.example.php
@@ -1,6 +1,6 @@
 <?php
 
-define('PUSHERAPP_APPID', '');
-define('PUSHERAPP_AUTHKEY', '');
-define('PUSHERAPP_SECRET', '');
-define('PUSHERAPP_HOST', 'http://api.pusherapp.com');
+const PUSHERAPP_APPID = '';
+const PUSHERAPP_AUTHKEY = '';
+const PUSHERAPP_SECRET = '';
+const PUSHERAPP_CLUSTER = 'eu';
diff --git a/tests/unit/AuthQueryStringTest.php b/tests/unit/AuthQueryStringTest.php
--- a/tests/unit/AuthQueryStringTest.php
+++ b/tests/unit/AuthQueryStringTest.php
@@ -1,41 +1,51 @@
 <?php
 
-class AuthQueryStringTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+
+class AuthQueryStringTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
-        $this->pusher = new Pusher\Pusher('thisisaauthkey', 'thisisasecret', 1);
+        $this->pusher = new Pusher('thisisaauthkey', 'thisisasecret', 1);
     }
 
-    public function testArrayImplode()
+    public function testArrayImplode(): void
     {
-        $val = array('testKey' => 'testValue');
+        $val = ['testKey' => 'testValue'];
 
         $expected = 'testKey=testValue';
-        $actual = Pusher\Pusher::array_implode('=', '&', $val);
+        $actual = Pusher::array_implode('=', '&', $val);
 
-        $this->assertEquals(
+        self::assertEquals(
             $expected,
             $actual,
             'auth signature valid'
         );
     }
 
-    public function testArrayImplodeWithTwoValues()
+    public function testArrayImplodeWithTwoValues(): void
     {
-        $val = array('testKey' => 'testValue', 'testKey2' => 'testValue2');
+        $val = ['testKey' => 'testValue', 'testKey2' => 'testValue2'];
 
         $expected = 'testKey=testValue&testKey2=testValue2';
-        $actual = Pusher\Pusher::array_implode('=', '&', $val);
+        $actual = Pusher::array_implode('=', '&', $val);
 
-        $this->assertEquals(
+        self::assertEquals(
             $expected,
             $actual,
             'auth signature valid'
         );
     }
 
-    public function testGenerateSignature()
+    public function testGenerateSignature(): void
     {
         $time = time();
         $auth_version = '1.0';
@@ -43,10 +53,10 @@ public function testGenerateSignature()
         $auth_key = 'thisisaauthkey';
         $auth_secret = 'thisisasecret';
         $request_path = '/channels/test_channel/events';
-        $query_params = array(
+        $query_params = [
             'name' => 'an_event',
-        );
-        $auth_query_string = Pusher\Pusher::build_auth_query_params(
+        ];
+        $auth_query_string = Pusher::build_auth_query_params(
             $auth_key,
             $auth_secret,
             $method,
@@ -66,7 +76,7 @@ public function testGenerateSignature()
             'name' => 'an_event'
         ];
 
-        $this->assertEquals(
+        self::assertEquals(
             $expected_query_params,
             $auth_query_string,
             'auth signature valid'
diff --git a/tests/unit/ChannelInfoUnitTest.php b/tests/unit/ChannelInfoUnitTest.php
--- a/tests/unit/ChannelInfoUnitTest.php
+++ b/tests/unit/ChannelInfoUnitTest.php
@@ -1,34 +1,44 @@
 <?php
 
-class ChannelInfoUnitTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+
+class ChannelInfoUnitTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
-        $this->pusher = new Pusher\Pusher('thisisaauthkey', 'thisisasecret', 1);
+        $this->pusher = new Pusher('thisisaauthkey', 'thisisasecret', 1);
     }
 
-    public function testTrailingColonChannelThrowsException()
+    public function testTrailingColonChannelThrowsException(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $this->pusher->get_channel_info('test_channel:');
     }
 
-    public function testLeadingColonChannelThrowsException()
+    public function testLeadingColonChannelThrowsException(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $this->pusher->get_channel_info(':test_channel');
     }
 
-    public function testLeadingColonNLChannelThrowsException()
+    public function testLeadingColonNLChannelThrowsException(): void
     {
         $this->expectException(\Pusher\PusherException::class);
-        
+
         $this->pusher->get_channel_info(':\ntest_channel');
     }
 
-    public function testTrailingColonNLChannelThrowsException()
+    public function testTrailingColonNLChannelThrowsException(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
diff --git a/tests/unit/CryptoTest.php b/tests/unit/CryptoTest.php
--- a/tests/unit/CryptoTest.php
+++ b/tests/unit/CryptoTest.php
@@ -1,101 +1,112 @@
 <?php
 
-class CryptoTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\PusherCrypto;
+use stdClass;
+
+class CryptoTest extends TestCase
 {
+    /**
+     * @var PusherCrypto
+     */
+    private $crypto;
+
     protected function setUp(): void
     {
         if (function_exists('sodium_crypto_secretbox')) {
-            $this->crypto = new Pusher\PusherCrypto('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
+            $this->crypto = new PusherCrypto('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
         } else {
-            $this->markTestSkipped('libSodium is not available, so end to end encryption is not available.');
+            self::markTestSkipped('libSodium is not available, so end to end encryption is not available.');
         }
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->crypto, 'Created new Pusher\PusherCrypto object');
+        self::assertNotNull($this->crypto, 'Created new \Pusher\PusherCrypto object');
     }
 
-    public function testValidMasterEncryptionKeys()
+    public function testValidMasterEncryptionKeys(): void
     {
-        $this->assertEquals('this is 32 bytes 123456789012345', Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMiBieXRlcyAxMjM0NTY3ODkwMTIzNDU='));
-        $this->assertEquals("this key has nonprintable char \x00", Pusher\PusherCrypto::parse_master_key('dGhpcyBrZXkgaGFzIG5vbnByaW50YWJsZSBjaGFyIAA='));
+        self::assertEquals('this is 32 bytes 123456789012345', PusherCrypto::parse_master_key('dGhpcyBpcyAzMiBieXRlcyAxMjM0NTY3ODkwMTIzNDU='));
+        self::assertEquals("this key has nonprintable char \x00", PusherCrypto::parse_master_key('dGhpcyBrZXkgaGFzIG5vbnByaW50YWJsZSBjaGFyIAA='));
     }
 
-    public function testInvalidMasterEncryptionKeyTooShort()
+    public function testInvalidMasterEncryptionKeyTooShort(): void
     {
         $this->expectException(\Pusher\PusherException::class);
         $this->expectExceptionMessage('32 bytes');
 
-        Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNA==');
+        PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNA==');
     }
 
-    public function testInvalidMasterEncryptionKeyTooLong()
+    public function testInvalidMasterEncryptionKeyTooLong(): void
     {
         $this->expectException(\Pusher\PusherException::class);
         $this->expectExceptionMessage('32 bytes');
 
-        Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNDU2');
+        PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNDU2');
     }
 
-    public function testInvalidMasterEncryptionKeyBase64TooShort()
+    public function testInvalidMasterEncryptionKeyBase64TooShort(): void
     {
         $this->expectException(\Pusher\PusherException::class);
         $this->expectExceptionMessage('32 bytes');
 
-        Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNA==');
+        PusherCrypto::parse_master_key('dGhpcyBpcyAzMSBieXRlcyAxMjM0NTY3ODkwMTIzNA==');
     }
 
-    public function testInvalidMasterEncryptionKeyBase64TooLong()
+    public function testInvalidMasterEncryptionKeyBase64TooLong(): void
     {
         $this->expectException(\Pusher\PusherException::class);
         $this->expectExceptionMessage('32 bytes');
 
-        Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMyBieXRlcyAxMjM0NTY3ODkwMTIzNDU2');
+        PusherCrypto::parse_master_key('dGhpcyBpcyAzMyBieXRlcyAxMjM0NTY3ODkwMTIzNDU2');
     }
 
-    public function testInvalidMasterEncryptionKeyBase64InvalidBase64()
+    public function testInvalidMasterEncryptionKeyBase64InvalidBase64(): void
     {
         $this->expectException(\Pusher\PusherException::class);
         $this->expectExceptionMessage('valid base64');
 
-        Pusher\PusherCrypto::parse_master_key('dGhpcyBpcyAzMyBi!XRlcyAxMjM0NTY3ODkw#TIzNDU2');
+        PusherCrypto::parse_master_key('dGhpcyBpcyAzMyBi!XRlcyAxMjM0NTY3ODkw#TIzNDU2');
     }
 
-    public function testGenerateSharedSecret()
+    public function testGenerateSharedSecret(): void
     {
         $expected = 'Rp+wpkNpL89qhqco1JkIG31AVXyU8PUVJBr1B2MvdoA=';
         // Check that the secret generation is generating consistent secrets
-        $this->assertEquals($expected, base64_encode($this->crypto->generate_shared_secret('private-encrypted-channel-a')));
+        self::assertEquals($expected, base64_encode($this->crypto->generate_shared_secret('private-encrypted-channel-a')));
 
         // Check that the secret generation is using the channel as a part of the generation
-        $this->assertNotEquals($expected, base64_encode($this->crypto->generate_shared_secret('private-encrypted-channel-b')));
+        self::assertNotEquals($expected, base64_encode($this->crypto->generate_shared_secret('private-encrypted-channel-b')));
 
         // Check that specifying a different key results in a different result
-        $crypto2 = new Pusher\PusherCrypto('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
-        $this->assertNotEquals($expected, base64_encode($crypto2->generate_shared_secret('private-encrypted-channel-a')));
+        $crypto2 = new PusherCrypto('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+        self::assertNotEquals($expected, base64_encode($crypto2->generate_shared_secret('private-encrypted-channel-a')));
     }
 
-    public function testGenerateSharedSecretNoChannel()
+    public function testGenerateSharedSecretNoChannel(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $this->crypto->generate_shared_secret('');
     }
 
-    public function testIsEncryptedChannel()
+    public function testIsEncryptedChannel(): void
     {
-        $this->assertEquals(true, Pusher\PusherCrypto::is_encrypted_channel('private-encrypted-test'));
-        $this->assertEquals(false, Pusher\PusherCrypto::is_encrypted_channel('private-encrypted'));
-        $this->assertEquals(false, Pusher\PusherCrypto::is_encrypted_channel('test-private-encrypted'));
+        self::assertEquals(true, PusherCrypto::is_encrypted_channel('private-encrypted-test'));
+        self::assertEquals(false, PusherCrypto::is_encrypted_channel('private-encrypted'));
+        self::assertEquals(false, PusherCrypto::is_encrypted_channel('test-private-encrypted'));
     }
 
-    public function testEncryptDecryptEventValid()
+    public function testEncryptDecryptEventValid(): void
     {
         $channel = 'private-encrypted-bla';
         $payload = "now that's what I call a payload!";
         $encrypted_payload = $this->crypto->encrypt_payload($channel, $payload);
-        $this->assertNotNull($encrypted_payload);
+        self::assertNotNull($encrypted_payload);
 
         // Create a mock Event object
         $event = new stdClass();
@@ -103,44 +114,44 @@ public function testEncryptDecryptEventValid()
         $event->channel = $channel;
         $decrypted_event = $this->crypto->decrypt_event($event);
         $decrypted_payload = $decrypted_event->data;
-        $this->assertEquals($payload, $decrypted_payload);
+        self::assertEquals($payload, $decrypted_payload);
     }
 
-    public function testEncryptPayloadNoChannel()
+    public function testEncryptPayloadNoChannel(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $channel = '';
         $payload = "now that's what I call a payload!";
         $encrypted_payload = $this->crypto->encrypt_payload($channel, $payload);
-        $this->assertEquals(false, $encrypted_payload);
+        self::assertEquals(false, $encrypted_payload);
     }
 
-    public function testEncryptPayloadPublicChannel()
+    public function testEncryptPayloadPublicChannel(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $channel = 'public-static-void-main';
         $payload = "now that's what I call a payload!";
         $encrypted_payload = $this->crypto->encrypt_payload($channel, $payload);
-        $this->assertEquals(false, $encrypted_payload);
+        self::assertEquals(false, $encrypted_payload);
     }
 
-    public function testDecryptPayloadWrongKey()
+    public function testDecryptPayloadWrongKey(): void
     {
         $this->expectException(\Pusher\PusherException::class);
 
         $channel = 'private-encrypted-bla';
         $payload = "now that's what I call a payload!";
         $encrypted_payload = $this->crypto->encrypt_payload($channel, $payload);
-        $this->assertNotNull($encrypted_payload);
+        self::assertNotNull($encrypted_payload);
         // create empty object with no properties
         $event = new stdClass();
         $event->data = $encrypted_payload;
         $event->channel = $channel;
 
-        $crypto2 = new Pusher\PusherCrypto('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+        $crypto2 = new PusherCrypto('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
         $decrypted_event = $crypto2->decrypt_event($event);
-        $this->assertEquals(false, $decrypted_event);
+        self::assertEquals(false, $decrypted_event);
     }
 }
diff --git a/tests/unit/PusherConstructorTest.php b/tests/unit/PusherConstructorTest.php
--- a/tests/unit/PusherConstructorTest.php
+++ b/tests/unit/PusherConstructorTest.php
@@ -1,65 +1,70 @@
 <?php
 
-class PusherConstructorTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+
+class PusherConstructorTest extends TestCase
 {
-    public function testUseTLSOptionWillSetHostAndPort()
+    public function testUseTLSOptionWillSetHostAndPort(): void
     {
-        $options = array('useTLS' => true);
-        $pusher = new Pusher\Pusher('app_key', 'app_secret', 'app_id', $options);
+        $options = ['useTLS' => true];
+        $pusher = new Pusher('app_key', 'app_secret', 'app_id', $options);
 
         $settings = $pusher->getSettings();
-        $this->assertEquals('https', $settings['scheme'], 'https');
-        $this->assertEquals('api-mt1.pusher.com', $settings['host']);
-        $this->assertEquals('443', $settings['port']);
+        self::assertEquals('https', $settings['scheme'], 'https');
+        self::assertEquals('api-mt1.pusher.com', $settings['host']);
+        self::assertEquals('443', $settings['port']);
     }
 
-    public function testUseTLSOptionWillBeOverwrittenByHostAndPortOptionsSetHostAndPort()
+    public function testUseTLSOptionWillBeOverwrittenByHostAndPortOptionsSetHostAndPort(): void
     {
-        $options = array(
+        $options = [
             'useTLS' => true,
             'host'   => 'test.com',
             'port'   => '3000',
-        );
-        $pusher = new Pusher\Pusher('app_key', 'app_secret', 'app_id', $options);
+        ];
+        $pusher = new Pusher('app_key', 'app_secret', 'app_id', $options);
 
         $settings = $pusher->getSettings();
-        $this->assertEquals('http', $settings['scheme']);
-        $this->assertEquals($options['host'], $settings['host']);
-        $this->assertEquals($options['port'], $settings['port']);
+        self::assertEquals('http', $settings['scheme']);
+        self::assertEquals($options['host'], $settings['host']);
+        self::assertEquals($options['port'], $settings['port']);
     }
 
-    public function testSchemeIsStrippedAndIgnoredFromHostInOptions()
+    public function testSchemeIsStrippedAndIgnoredFromHostInOptions(): void
     {
-        $options = array(
+        $options = [
             'host' => 'http://test.com',
-        );
-        $pusher = new Pusher\Pusher('app_key', 'app_secret', 'app_id', $options);
+        ];
+        $pusher = new Pusher('app_key', 'app_secret', 'app_id', $options);
 
         $settings = $pusher->getSettings();
-        $this->assertEquals('https', $settings['scheme']);
-        $this->assertEquals('test.com', $settings['host']);
+        self::assertEquals('https', $settings['scheme']);
+        self::assertEquals('test.com', $settings['host']);
     }
 
-    public function testClusterSetsANewHost()
+    public function testClusterSetsANewHost(): void
     {
-        $options = array(
+        $options = [
             'cluster' => 'eu',
-        );
-        $pusher = new Pusher\Pusher('app_key', 'app_secret', 'app_id', $options);
+        ];
+        $pusher = new Pusher('app_key', 'app_secret', 'app_id', $options);
 
         $settings = $pusher->getSettings();
-        $this->assertEquals('api-eu.pusher.com', $settings['host']);
+        self::assertEquals('api-eu.pusher.com', $settings['host']);
     }
 
-    public function testClusterOptionIsOverriddenByHostIfItExists()
+    public function testClusterOptionIsOverriddenByHostIfItExists(): void
     {
-        $options = array(
+        $options = [
             'cluster' => 'eu',
             'host'    => 'api.staging.pusher.com',
-        );
-        $pusher = new Pusher\Pusher('app_key', 'app_secret', 'app_id', $options);
+        ];
+        $pusher = new Pusher('app_key', 'app_secret', 'app_id', $options);
 
         $settings = $pusher->getSettings();
-        $this->assertEquals('api.staging.pusher.com', $settings['host']);
+        self::assertEquals('api.staging.pusher.com', $settings['host']);
     }
 }
diff --git a/tests/unit/SocketAuthTest.php b/tests/unit/SocketAuthTest.php
--- a/tests/unit/SocketAuthTest.php
+++ b/tests/unit/SocketAuthTest.php
@@ -1,89 +1,100 @@
 <?php
 
-class SocketAuthTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+use Pusher\PusherException;
+
+class SocketAuthTest extends TestCase
 {
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
-        $this->pusher = new Pusher\Pusher('thisisaauthkey', 'thisisasecret', 1, array());
+        $this->pusher = new Pusher('thisisaauthkey', 'thisisasecret', 1, []);
     }
 
-    public function testObjectConstruct()
+    public function testObjectConstruct(): void
     {
-        $this->assertNotNull($this->pusher, 'Created new Pusher\Pusher object');
+        $this->assertNotNull($this->pusher, 'Created new \Pusher\Pusher object');
     }
 
-    public function testSocketAuthKey()
+    public function testSocketAuthKey(): void
     {
         $socket_auth = $this->pusher->socket_auth('testing_pusher-php', '1.1');
-        $this->assertEquals(
+        self::assertEquals(
             '{"auth":"thisisaauthkey:751ccc12aeaa79d46f7c199bced5fa47527d3480b51fe61a0bd10438241bd52d"}',
             $socket_auth,
             'Socket auth key valid'
         );
     }
 
-    public function testComplexSocketAuthKey()
+    public function testComplexSocketAuthKey(): void
     {
         $socket_auth = $this->pusher->socket_auth('-azAZ9_=@,.;', '45055.28877557');
-        $this->assertEquals(
+        self::assertEquals(
             '{"auth":"thisisaauthkey:d1c20ad7684c172271f92c108e11b45aef07499b005796ae1ec5beb924f361c4"}',
             $socket_auth,
             'Socket auth key valid'
         );
     }
 
-    public function testTrailingColonSocketIDThrowsException()
+    public function testTrailingColonSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('testing_pusher-php', '1.1:');
     }
 
-    public function testLeadingColonSocketIDThrowsException()
+    public function testLeadingColonSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('testing_pusher-php', ':1.1');
     }
 
-    public function testLeadingColonNLSocketIDThrowsException()
+    public function testLeadingColonNLSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('testing_pusher-php', ':\n1.1');
     }
 
-    public function testTrailingColonNLSocketIDThrowsException()
+    public function testTrailingColonNLSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('testing_pusher-php', '1.1\n:');
     }
 
-    public function testTrailingColonChannelThrowsException()
+    public function testTrailingColonChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('test_channel:', '1.1');
     }
 
-    public function testLeadingColonChannelThrowsException()
+    public function testLeadingColonChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth(':test_channel', '1.1');
     }
 
-    public function testLeadingColonNLChannelThrowsException()
+    public function testLeadingColonNLChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth(':\ntest_channel', '1.1');
     }
 
-    public function testTrailingColonNLChannelThrowsException()
+    public function testTrailingColonNLChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $this->pusher->socket_auth('test_channel\n:', '1.1');
     }
diff --git a/tests/unit/TriggerUnitTest.php b/tests/unit/TriggerUnitTest.php
--- a/tests/unit/TriggerUnitTest.php
+++ b/tests/unit/TriggerUnitTest.php
@@ -1,88 +1,107 @@
 <?php
 
-class TriggerUnitTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+use Pusher\PusherException;
+
+class TriggerUnitTest extends TestCase
 {
+    /**
+     * @var array
+     */
+    private $localData;
+    /**
+     * @var string
+     */
+    private $eventName;
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
-        $this->pusher = new Pusher\Pusher('thisisaauthkey', 'thisisasecret', 1);
+        $this->pusher = new Pusher('thisisaauthkey', 'thisisasecret', 1);
         $this->eventName = 'test_event';
-        $this->data = array();
+        $this->localData = [];
     }
 
-    public function testTrailingColonChannelThrowsException()
+    public function testTrailingColonChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel:', $this->eventName, $this->data);
+        $this->pusher->trigger('test_channel:', $this->eventName, $this->localData);
     }
 
-    public function testLeadingColonChannelThrowsException()
+    public function testLeadingColonChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger(':test_channel', $this->eventName, $this->data);
+        $this->pusher->trigger(':test_channel', $this->eventName, $this->localData);
     }
 
-    public function testLeadingColonNLChannelThrowsException()
+    public function testLeadingColonNLChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger(':\ntest_channel', $this->eventName, $this->data);
+        $this->pusher->trigger(':\ntest_channel', $this->eventName, $this->localData);
     }
 
-    public function testTrailingColonNLChannelThrowsException()
+    public function testTrailingColonNLChannelThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel\n:', $this->eventName, $this->data);
+        $this->pusher->trigger('test_channel\n:', $this->eventName, $this->localData);
     }
 
-    public function testChannelArrayThrowsException()
+    public function testChannelArrayThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger(array('this_one_is_okay', 'test_channel\n:'), $this->eventName, $this->data);
+        $this->pusher->trigger(['this_one_is_okay', 'test_channel\n:'], $this->eventName, $this->localData);
     }
 
-    public function testTrailingColonSocketIDThrowsException()
+    public function testTrailingColonSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel:', $this->eventName, $this->data, array('socket_id' => '1.1:'));
+        $this->pusher->trigger('test_channel:', $this->eventName, $this->localData, ['socket_id' => '1.1:']);
     }
 
-    public function testLeadingColonSocketIDThrowsException()
+    public function testLeadingColonSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel:', $this->eventName, $this->data, array('socket_id' => ':1.1'));
+        $this->pusher->trigger('test_channel:', $this->eventName, $this->localData, ['socket_id' => ':1.1']);
     }
 
-    public function testLeadingColonNLSocketIDThrowsException()
+    public function testLeadingColonNLSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel:', $this->eventName, $this->data, array('socket_id' => ':\n1.1'));
+        $this->pusher->trigger('test_channel:', $this->eventName, $this->localData, ['socket_id' => ':\n1.1']);
     }
 
-    public function testTrailingColonNLSocketIDThrowsException()
+    public function testTrailingColonNLSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel:', $this->eventName, $this->data, array('socket_id' => '1.1\n:'));
+        $this->pusher->trigger('test_channel:', $this->eventName, $this->localData, ['socket_id' => '1.1\n:']);
     }
 
-    public function testFalseSocketIDThrowsException()
+    public function testFalseSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel', $this->eventName, $this->data, array('socket_id' => false));
+        $this->pusher->trigger('test_channel', $this->eventName, $this->localData, ['socket_id' => false]);
     }
 
-    public function testEmptyStrSocketIDThrowsException()
+    public function testEmptyStrSocketIDThrowsException(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
-        $this->pusher->trigger('test_channel', $this->eventName, $this->data, array('socket_id' => ''));
+        $this->pusher->trigger('test_channel', $this->eventName, $this->localData, ['socket_id' => '']);
     }
 }
diff --git a/tests/unit/WebhookTest.php b/tests/unit/WebhookTest.php
--- a/tests/unit/WebhookTest.php
+++ b/tests/unit/WebhookTest.php
@@ -1,48 +1,63 @@
 <?php
 
-class WebhookTest extends PHPUnit\Framework\TestCase
+namespace unit;
+
+use PHPUnit\Framework\TestCase;
+use Pusher\Pusher;
+use Pusher\PusherException;
+
+class WebhookTest extends TestCase
 {
+    /**
+     * @var string
+     */
+    private $auth_key;
+    /**
+     * @var Pusher
+     */
+    private $pusher;
+
     protected function setUp(): void
     {
         $this->auth_key = 'thisisaauthkey';
-        $this->pusher = new Pusher\Pusher($this->auth_key, 'thisisasecret', 1);
+        $this->pusher = new Pusher($this->auth_key, 'thisisasecret', 1);
     }
 
-    public function testValidWebhookSignature()
+    public function testValidWebhookSignature(): void
     {
         $signature = '40e0ad3b9aa49529322879e84de1aaaf18bde1efe839ca263d540cc865510d25';
         $body = '{"hello":"world"}';
-        $headers = array(
+        $headers = [
             'X-Pusher-Key'       => $this->auth_key,
             'X-Pusher-Signature' => $signature,
-        );
+        ];
 
         $this->pusher->ensure_valid_signature($headers, $body);
 
-        $this->assertTrue(true);
+        self::assertTrue(true);
     }
 
-    public function testInvalidWebhookSignature()
+    public function testInvalidWebhookSignature(): void
     {
-        $this->expectException(\Pusher\PusherException::class);
+        $this->expectException(PusherException::class);
 
         $signature = 'potato';
         $body = '{"hello":"world"}';
-        $headers = array(
+        $headers = [
             'X-Pusher-Key'       => $this->auth_key,
             'X-Pusher-Signature' => $signature,
-        );
-        $wrong_signature = $this->pusher->ensure_valid_signature($headers, $body);
+        ];
+        $this->pusher->ensure_valid_signature($headers, $body);
     }
 
-    public function testDecodeWebhook()
+    public function testDecodeWebhook(): void
     {
-        $headers_json = '{"X-Pusher-Key":"'.$this->auth_key.'","X-Pusher-Signature":"a19cab2af3ca1029257570395e78d5d675e9e700ca676d18a375a7083178df1c"}';
+        $headers_json = '{"X-Pusher-Key":"' . $this->auth_key . '","X-Pusher-Signature":"a19cab2af3ca1029257570395e78d5d675e9e700ca676d18a375a7083178df1c"}';
         $body = '{"time_ms":1530710011901,"events":[{"name":"client_event","channel":"private-my-channel","event":"client-event","data":"Unencrypted","socket_id":"240621.35780774"}]}';
-        $headers = json_decode($headers_json, true);
+        $headers = json_decode($headers_json, true, 512, JSON_THROW_ON_ERROR);
 
         $decodedWebhook = $this->pusher->webhook($headers, $body);
-        $this->assertEquals(1530710011901, $decodedWebhook->get_time_ms());
-        $this->assertEquals(1, count($decodedWebhook->get_events()));
+        self::assertEquals(1530710011901, $decodedWebhook->get_time_ms());
+        self::assertCount(1, $decodedWebhook->get_events());
     }
 }