diff --git a/composer.json b/composer.json index 3056ffa82..aa3ceafe4 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "pocketmine/binaryutils": "^0.1.0", "pocketmine/nbt": "dev-master", "pocketmine/math": "dev-master", - "pocketmine/snooze": "^0.1.0" + "pocketmine/snooze": "^0.1.0", + "daverandom/callback-validator": "dev-master" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 9d8246e6a..8269f9a20 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,48 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d6cbb4a2c58dae0906bf9c13ef4a1f2c", + "content-hash": "4793017ff4b236529dc5072bd06f8754", "packages": [ + { + "name": "daverandom/callback-validator", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/CallbackValidator.git", + "reference": "d87a08cddbc6099816ed01e50ce25cdfc43b542f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/CallbackValidator/zipball/d87a08cddbc6099816ed01e50ce25cdfc43b542f", + "reference": "d87a08cddbc6099816ed01e50ce25cdfc43b542f", + "shasum": "" + }, + "require": { + "ext-reflection": "*", + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "DaveRandom\\CallbackValidator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "cw@daverandom.com" + } + ], + "description": "Tools for validating callback signatures", + "time": "2017-04-03T15:22:41+00:00" + }, { "name": "fgrosse/phpasn1", "version": "v2.1.1", @@ -377,7 +417,8 @@ "pocketmine/raklib": 20, "pocketmine/spl": 20, "pocketmine/nbt": 20, - "pocketmine/math": 20 + "pocketmine/math": 20, + "daverandom/callback-validator": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index efbb0b5b0..6b9d148f1 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use pocketmine\utils\Utils; + /** * Manages general-purpose worker threads used for processing asynchronous tasks, and the tasks submitted to those * workers. @@ -84,6 +86,7 @@ class AsyncPool{ * @param \Closure $hook */ public function addWorkerStartHook(\Closure $hook) : void{ + Utils::validateCallableSignature(function(int $worker) : void{}, $hook); $this->workerStartHooks[spl_object_hash($hook)] = $hook; foreach($this->workers as $i => $worker){ $hook($i); diff --git a/src/pocketmine/scheduler/ClosureTask.php b/src/pocketmine/scheduler/ClosureTask.php index 8ada271ff..f023173d4 100644 --- a/src/pocketmine/scheduler/ClosureTask.php +++ b/src/pocketmine/scheduler/ClosureTask.php @@ -45,6 +45,7 @@ class ClosureTask extends Task{ * @param \Closure $closure Must accept only ONE parameter, $currentTick */ public function __construct(\Closure $closure){ + Utils::validateCallableSignature(function(int $currentTick) : void{}, $closure); $this->closure = $closure; } diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 5989de29f..bd13a3c6d 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -27,6 +27,7 @@ declare(strict_types=1); namespace pocketmine\utils; +use DaveRandom\CallbackValidator\CallbackType; use pocketmine\ThreadManager; /** @@ -550,4 +551,20 @@ class Utils{ throw new \InvalidArgumentException("Class $className cannot be constructed"); } } + + /** + * Verifies that the given callable is compatible with the desired signature. Throws a TypeError if they are + * incompatible. + * + * @param callable $signature Dummy callable with the required parameters and return type + * @param callable $subject Callable to check the signature of + * + * @throws \DaveRandom\CallbackValidator\InvalidCallbackException + * @throws \TypeError + */ + public static function validateCallableSignature(callable $signature, callable $subject) : void{ + if(!($sigType = CallbackType::createFromCallable($signature))->isSatisfiedBy($subject)){ + throw new \TypeError("Declaration of callable `" . CallbackType::createFromCallable($subject) . "` must be compatible with `" . $sigType . "`"); + } + } }