{"id":20732144,"url":"https://github.com/ailixter/gears-watchedcall","last_synced_at":"2025-07-06T22:36:58.698Z","repository":{"id":56942729,"uuid":"201519279","full_name":"ailixter/gears-watchedcall","owner":"ailixter","description":"Hooks before/after any method call","archived":false,"fork":false,"pushed_at":"2019-08-17T13:54:07.000Z","size":9,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-18T00:30:44.726Z","etag":null,"topics":["access-control","contract","decorator","managed","postcondition","precondition"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ailixter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-09T18:15:19.000Z","updated_at":"2019-08-16T14:57:57.000Z","dependencies_parsed_at":"2022-08-21T07:50:30.425Z","dependency_job_id":null,"html_url":"https://github.com/ailixter/gears-watchedcall","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ailixter%2Fgears-watchedcall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ailixter%2Fgears-watchedcall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ailixter%2Fgears-watchedcall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ailixter%2Fgears-watchedcall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ailixter","download_url":"https://codeload.github.com/ailixter/gears-watchedcall/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243013754,"owners_count":20221785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","contract","decorator","managed","postcondition","precondition"],"created_at":"2024-11-17T05:17:55.499Z","updated_at":"2025-03-11T10:25:51.681Z","avatar_url":"https://github.com/ailixter.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gears-watchedcall\nHooks before/after any method call\n\n## Before a call\n\n```php\n    use Ailixter\\Gears\\CallWatching;\n    use const Ailixter\\Gears\\WatchedCall\\BEFORE_CALL;\n    use const Ailixter\\Gears\\WatchedCall\\AFTER_CALL;\n\n    class Example\n    {\n        use CallWatching;\n        /**\n         * @access public\n         * via private modifier\n         */\n        private function watchedMethod($arg1, $arg2)\n        {\n            return $arg1 + $arg2;\n        }\n    }\n\n    $example = new Example;\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable $callable, array $args) {\n        // $callable is guaranteed to be in form [object, method]\n        [$object, $method] = $callable;\n        // inspect $args\n        // ...\n        // do something else\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 5\n```\n\n### Loud Access Check\n```php\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable $callable) {\n        if (!User::canAccess($callable)) {\n            throw new UserAccessException;\n        }\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // exception\n```\n\n### Quiet Access Check\n```php\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable \u0026$callable) {\n        if (!User::canAccess($callable)) {\n            // just return something acceptable\n            $callable = function () { return null; }\n        }\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // null\n```\n\n### Fallback For Unknown Methods\n```php\n    $example-\u003eattachToWatch(BEFORE_CALL, 'unknownMethod', function (callable \u0026$callable) {\n        // just return something acceptable\n        $callable = function () { return null; }\n    });\n    $result = $example-\u003eunknownMethod(2, 3); // null\n```\n\n### Tampering Routine\n```php\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable \u0026$callable) {\n        $callable = 'min';\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 2\n```\n\n### Tampering Arguments\n```php\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable $callable, array \u0026$args) {\n        $args = array_map(function (int $arg) { return $arg * $arg; }, $args);\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 13\n```\n\n### Classic Decoration\n```php\n    $done = false;\n    $example-\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable \u0026$callable) use (\u0026$done) {\n        if ($done) return;\n        $done = true;\n        $callable = function (...$args) use ($callable) {\n            return $callable(...array_map(function (int $arg) { return $arg * $arg; }, $args)) + 1;\n        };\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 14\n```\n\n## After a call\n\n### Result Substitution\n```php\n    $example-\u003eattachToWatch(AFTER_CALL, 'watchedMethod', function (callable $callable, array $args, \u0026$result) {\n        $result *= 2;\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 10\n```\n\n### Loud Result Check\n```php\n    $example-\u003eattachToWatch(AFTER_CALL, 'watchedMethod', function (callable $callable, array $args, $result) {\n        if (array_sum($args) != $result) {\n            throw new CalculationError;\n        }\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 10\n```\n\n### Quiet Result Check\n```php\n    $example-\u003eattachToWatch(AFTER_CALL, 'watchedMethod', function (callable $callable, array $args, \u0026$result) {\n        if (array_sum($args) != $result) {\n            $result = null;\n        }\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 10\n```\n\n## Decoration\n```php\n    $example\n    -\u003eattachToWatch(BEFORE_CALL, 'watchedMethod', function (callable $callable, array \u0026$args) {\n        $args = array_map(function (int $arg) { return $arg * $arg; }, $args);\n    })\n    -\u003eattachToWatch(AFTER_CALL, 'watchedMethod', function (callable $callable, array $args, \u0026$result) {\n        $result += 1\n    });\n    $result = $example-\u003ewatchedMethod(2, 3); // 14\n```\n\n## Watching via Delegation\n```php\n    class Delegate\n    {\n        public function watchedMethod($arg1, $arg2)\n        {\n            return $arg1 + $arg2;\n        }\n    }\n\n    class Example\n    {\n        use CallWatching;\n        private $delegate;\n        public function __construct(Delegate $delegate)\n        {\n            $this-\u003edelegate = $delegate;\n        }\n        /**\n         * note overriding\n         */\n        protected function getWatchedObject()\n        {\n            return $this-\u003edelegate;\n        }\n    }\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Failixter%2Fgears-watchedcall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Failixter%2Fgears-watchedcall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Failixter%2Fgears-watchedcall/lists"}