{"id":20776803,"url":"https://github.com/phpactor/flow","last_synced_at":"2026-04-20T08:04:39.158Z","repository":{"id":45114573,"uuid":"443186623","full_name":"phpactor/flow","owner":"phpactor","description":null,"archived":false,"fork":false,"pushed_at":"2022-01-07T11:27:25.000Z","size":108,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-18T08:19:49.421Z","etag":null,"topics":[],"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/phpactor.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":"2021-12-30T21:17:16.000Z","updated_at":"2022-01-07T11:27:26.000Z","dependencies_parsed_at":"2022-09-14T07:32:12.665Z","dependency_job_id":null,"html_url":"https://github.com/phpactor/flow","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpactor%2Fflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpactor%2Fflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpactor%2Fflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phpactor%2Fflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phpactor","download_url":"https://codeload.github.com/phpactor/flow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243119662,"owners_count":20239319,"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":[],"created_at":"2024-11-17T13:11:57.360Z","updated_at":"2026-04-20T08:04:34.117Z","avatar_url":"https://github.com/phpactor.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Flow\n====\n\nAttempt to create a better code analysis engine using an intermediate\nrepresentation.\n\nIt aims to fundamentally replace [worse-reflection](https://github.com/phpactor/worse-reflection). It will:\n\n- Be based on an _intermediate representation_ (IR) which augments the underlying AST\n  with types.\n- Have a modern type engine\n- Feature improved docblock parsing (via. [phpactor-docblock](https://github.com/phpactor/docblock-parser)\n- Compeletely abstract the underlying AST from the client.\n- Allow the IR to be queried.\n- Provide positions of all IR elements to facilitate refactoring.\n\nExample\n-------\n\nIR navigation (completion):\n\n```\n$element = $flow-\u003eparse($source);\n$element = $element-\u003efindDescendantAtPosition(10);\n$element-\u003etype(); // e.g. new UnionType(new StringType(), new NullType());\n```\n\nIR navigation (diagnostics):\n\n```\n$root = $flow-\u003eparse($source);\n$callsToNonExistingMethods = $root-\u003efindDescendantNodes(MethodCallElement::class)-\u003efilter(\n    fn(MethodCallElement $e) =\u003e false === $e-\u003etargetExists()\n);\n\nforeach ($callsToNonExistingMethods as $nonExistingCall) {\n    $nonExistingCall-\u003erange()-\u003estart()-\u003etoInt(); // start byte offset\n    $nonExistingCall-\u003erange()-\u003eend()-\u003etoInt();   // end byte offset  \n}\n```\n\nReflection (with templating):\n\n```\n/**\n * @template T\n */\nclass Foobar { \n    /** @return T */\n    function bar(): mixed { \n        // ... \n    } \n\n    // ...\n}\n\n$class = $flow-\u003ereflectClass('Foobar', [\n    new StringType('Hello'),\n    new ClassType('Foobar'),\n]);\n\n$class-\u003emethods()-\u003eget('bar')-\u003etype(); // new StringType('Hello');\n```\n\nPrinciples\n----------\n\n- **Performant**: Must be fast for realtime analysis\n- **Tolerant**: Should not produce runtime errors from provided code\n- **Maintainable**: Easy to fix bugs and extend\n\nAlternative Apporaches\n----------------------\n\n- No IR\n- Use hash table to store type information\n-\n\n```\n[\n    $n1 =\u003e StringType(\"foo\"),\n    $n2 =\u003e ClassType(\"Bar\"),\n]\n```\n\n```\n$type = $interpreter-\u003einterpret($node);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphpactor%2Fflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphpactor%2Fflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphpactor%2Fflow/lists"}