{"id":23512764,"url":"https://github.com/baethon/union.php","last_synced_at":"2025-05-13T19:29:11.286Z","repository":{"id":56964629,"uuid":"141732459","full_name":"baethon/union.php","owner":"baethon","description":"Union type for PHP","archived":false,"fork":false,"pushed_at":"2020-08-24T13:02:24.000Z","size":32,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-16T21:18:10.282Z","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/baethon.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":"2018-07-20T16:06:20.000Z","updated_at":"2020-08-24T14:37:57.000Z","dependencies_parsed_at":"2022-08-21T09:20:34.308Z","dependency_job_id":null,"html_url":"https://github.com/baethon/union.php","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Funion.php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Funion.php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Funion.php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Funion.php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baethon","download_url":"https://codeload.github.com/baethon/union.php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254012554,"owners_count":21999285,"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-12-25T13:19:23.480Z","updated_at":"2025-05-13T19:29:11.251Z","avatar_url":"https://github.com/baethon.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# baethon/union\n\nProvides utilities to define tagged unions.\n\n# Tagged unions?\n\nI'm not good with words, yet folks from [Folktale](https://folktale.origamitower.com/api/v2.1.0/en/folktale.adt.union.html) describe it nicely:\n\n\u003e Modelling data is important for a range of reasons. From performance to correctness to safety. Tagged unions give you a way of modelling choices that forces the correct handling of them, unlike predicate-based branching, such as the one used by if statements and other common control flow structures.\n\n# Installation\n\n```bash\ncomposer require baethon/union\n```\n\n# Usage\n\nTo create a tag union it's required to create a class which extends `Baethon\\Union\\AbstractUnion`.\n\n```php\nclass Maybe extends \\Baethon\\Union\\AbstractUnion\n{\n}\n```\n\nAlso you need to define tags which will represent state of the union.\n\n```php\nclass Maybe extends \\Baethon\\Union\\AbstractUnion\n{\n\tconst SOME = 'Some:x';\n\n\tconst NONE = 'None';\n}\n```\n\n## Signatures\n\nEach tag has a definition (called _signature_), which can be defined using following syntax:\n\n```\n{Name}[:[param1[, param2[, ...[, paramN]]]]]\n```\n\nParameters define whether a tag will hold any value(s) (called _arguments_). They're optional.\n\n## Working with unions\n\nUnion can be invoked using static constructor:\n\n```php\n$some = Maybe::Some(1);\n```\n\nTo work with the state of the union you should use `matchWith()`. It will return the value returned by the matching callback:\n\n```php\nfunction addTen(Maybe $maybe) {\n\treturn $maybe-\u003ematchWith([\n\t\t'Some' =\u003e function ($x) {\n\t\t\treturn $x + 10;\n\t\t},\n\t\t'None' =\u003e function () {\n\t\t\tthrow new \\Exception('Sorry, can\\'t add a number to nothing');\n\t\t}\n\t]);\n}\n\naddTen($some); // 11\n```\n\n`matchWith()` will check if all possible branches are mapped:\n\n* if a tag is not covered by map `UnderflowException` will be thrown\n* if map covers more tags than defined ones it will throw 'OverflowException'. \n\nIt's possible to use wildcard map to cover all other cases:\n\n```php\n$some-\u003ematchWith([\n\t'*' =\u003e function () {\n\t\treturn 100;\n\t}\n]); // 100\n```\n\nYou can use defined const values in mapping:\n\n```php\n$some-\u003ematchWith([\n\tMaybe::SOME =\u003e function () {},\n\tMaybe::NONE =\u003e function () {}\n]);\n```\n\n# Testing\n\n```\n./vendor/bin/phpunit\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaethon%2Funion.php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaethon%2Funion.php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaethon%2Funion.php/lists"}