{"id":13828355,"url":"https://github.com/php-deal/framework","last_synced_at":"2026-01-13T23:47:59.782Z","repository":{"id":13736705,"uuid":"16431046","full_name":"php-deal/framework","owner":"php-deal","description":"Design by Contract framework for PHP","archived":false,"fork":false,"pushed_at":"2022-03-14T18:12:59.000Z","size":147,"stargazers_count":253,"open_issues_count":3,"forks_count":21,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-09-23T10:40:00.276Z","etag":null,"topics":["contracts-programming","dbc","design-by-contracts","invariants","php","preconditions"],"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/php-deal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-01T08:54:25.000Z","updated_at":"2025-08-02T09:03:38.000Z","dependencies_parsed_at":"2022-08-10T09:02:28.994Z","dependency_job_id":null,"html_url":"https://github.com/php-deal/framework","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/php-deal/framework","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-deal%2Fframework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-deal%2Fframework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-deal%2Fframework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-deal%2Fframework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/php-deal","download_url":"https://codeload.github.com/php-deal/framework/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-deal%2Fframework/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28405362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["contracts-programming","dbc","design-by-contracts","invariants","php","preconditions"],"created_at":"2024-08-04T09:02:42.773Z","updated_at":"2026-01-13T23:47:59.751Z","avatar_url":"https://github.com/php-deal.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"PhpDeal\n-------\n\nDesign by Contract framework for PHP\n\nWhat is Design by Contract?\n---------------------------\n\nThe specification of a class or interface is the collection of non-private items provided as services to the\ncaller, along with instructions for their use, as stated in phpDoc. [Design By Contract](http://en.wikipedia.org/wiki/Design_by_contract) is an effective technology\nfor creating a specification.\n\nThe fundamental idea of Design By Contract is to treat the services offered by a class or interface as a\ncontract between the class (or interface) and its caller. Here, the word \"contract\" is meant to convey a kind\nof formal, unambiguous agreement between two parties:\n\n* requirements upon the caller made by the class\n* promises made by the class to the caller\n\nIf the caller fulfills the requirements, then the class promises to deliver some well-defined service. Some\nchanges to a specification/contract will break the caller, and some won't. For determining if a change will\nbreak a caller, C++ FAQs uses the memorable phrase \"require no more, promise no less\": if the new specification\ndoes not require more from the caller than before, and if it does not promise to deliver less than before,\nthen the new specification is compatible with the old, and will not break the caller.\n\n[![Build Status](https://api.travis-ci.org/php-deal/framework.png?branch=1.x)](https://travis-ci.org/php-deal/framework)\n[![GitHub release](https://img.shields.io/github/release/php-deal/framework.svg)](https://github.com/php-deal/framework/releases/latest)\n[![Code Coverage](https://scrutinizer-ci.com/g/php-deal/framework/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/php-deal/framework/?branch=1.x)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/php-deal/framework/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/php-deal/framework/?branch=1.x)\n[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D7.1-blue.svg)](https://php.net/)\n[![License](https://img.shields.io/packagist/l/php-deal/framework.svg)](https://packagist.org/packages/php-deal/framework)\n\nInstallation\n------------\n\nPhpDeal framework can be installed with composer. Installation is quite easy, just ask composer to download\nthe framework with its dependencies by running the command:\n\n``` bash\n$ composer require php-deal/framework\n```\n\nSetup\n-----\n\nPut the following code at the beginning of your \napplication entry point or require it from an external file. \n\n```php\n\n$instance = ContractApplication::getInstance();\n$instance-\u003einit(array(\n    'debug'    =\u003e true,\n    'appDir'   =\u003e __DIR__,\n    'excludePaths' =\u003e [\n        __DIR__ . '/vendor'\n    ],\n    'includePaths' =\u003e [\n\n    ],\n    'cacheDir' =\u003e __DIR__.'/cache/',\n));\n```\n\nSymfony setup\n-------------\n\nPut the following code in app_dev.php and adapt it to match\nyour folder structure. The appDir must point to the folder containing\nthe src files, not the document root folder ! \n\n```php\n\n$instance = ContractApplication::getInstance();\n$instance-\u003einit(array(\n    'debug'    =\u003e true,\n    'appDir'   =\u003e __DIR__ . '/../src',\n    'excludePaths' =\u003e [\n\n    ],\n    'includePaths' =\u003e [\n\n    ],\n    'cacheDir' =\u003e __DIR__.'/var/cache/',\n));\n```\n\n\nPre and Post Contracts\n----------------------\n\nThe pre contracts specify the preconditions (requirements) before a statement is executed. The most typical use\nof this would be in validating the parameters to a function. The post contracts (promises) validate the result\nof the statement. The most typical use of this would be in validating the return value of a method and of\nany side effects it has. The syntax is:\n\n```php\n\u003c?php\nnamespace Vendor\\Namespace;\n\nuse PhpDeal\\Annotation as Contract; //import DbC annotations\n\n/**\n * Some account class\n */\nclass Account\n{\n\n    /**\n     * Current balance\n     *\n     * @var float\n     */\n    protected $balance = 0.0;\n\n    /**\n     * Deposits fixed amount of money to the account\n     *\n     * @param float $amount\n     *\n     * @Contract\\Verify(\"$amount\u003e0 \u0026\u0026 is_numeric($amount)\")\n     * @Contract\\Ensure(\"$this-\u003ebalance == $__old-\u003ebalance+$amount\")\n     */\n    public function deposit($amount)\n    {\n        $this-\u003ebalance += $amount;\n    }\n}\n```\n\nBy definition, if a pre contract fails, then the body received bad parameters. A ContractViolation exception\nis thrown.\nIf a post contract fails, then there is a bug in the body. A ContractViolation exception is thrown.\n\nInvariants\n----------\n\nInvariants are used to specify characteristics of a class that always must be true (except while executing a\nprotected or private member function).\n\nThe invariant is a contract saying that the asserts must hold true. The invariant is checked when a class constructor\n completes and at the end of the class public methods:\n\n```php\n\u003c?php\nnamespace Vendor\\Namespace;\n\nuse PhpDeal\\Annotation as Contract; //import DbC annotations\n\n/**\n * Some account class\n *\n * @Contract\\Invariant(\"$this-\u003ebalance \u003e 0\")\n */\nclass Account\n{\n\n    /**\n     * Current balance\n     *\n     * @var float\n     */\n    protected $balance = 0.0;\n\n    /**\n     * Deposits fixed amount of money to the account\n     *\n     * @param float $amount\n     */\n    public function deposit($amount)\n    {\n        $this-\u003ebalance += $amount;\n    }\n}\n```\nInvariants contain assert expressions, and so when they fail, they throw a ContractViolation exception.\n\n__NOTE__: The code in the invariant may not call any public non-static members of the class, either directly or\nindirectly. Doing so will result in a stack overflow, as the invariant will wind up being called in an\ninfinitely recursive manner.\n\nContract propagation\n----------\n\nThere a some differences in inheritance of the contracts:\n\n1. Ensure\n  - if provided `Ensure` will automatically inherit all contracts from parent class or interface\n2. Verify\n  - if provided `Verify` will _not_ inherit contracts from parent class or interface\n  - to inherit contracts you will need to provide `@inheritdoc` or the `Inherit` contract\n3. Invariant\n  - if provided `Invariant` will inherit all contracts from parent class or interface\n4. Inherit\n  - if provided `Inherit` will inherit all contracts from the given level (class, method) without the\n  need to provide a contract on your current class or method\n  \n__Notes__: \n- The parsing of a contract only happens __IF__ you provide any given annotation from this package.\nWithout it, your contracts won't work!\n- The annotation __must not__ have curly braces (`{}`) otherwise the annotation reader can't find them.\n\n```php\n\nclass Foo extends FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Verify(\"$amount != 1\")\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n    \nclass FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Verify(\"$amount != 2\")\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n    \n```\n\n`Foo::bar` accepts `2` literal as a parameter and does not accept `1`.\n\nWith @inheritdoc:\n\n```php\n\nclass Foo extends FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Verify(\"$amount != 1\")\n     * {@inheritdoc}\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n    \nclass FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Verify(\"$amount != 2\")\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n    \n```\n\n`Foo::bar` does not accept `1` and `2` literals as a parameter.\n\n\nFor postconditions (Ensure and Invariants contracts) subclasses inherit contracts and they don't need `@inheritdoc`. Example:\n\n```php\n    \n/**\n * @Contract\\Invariant(\"$this-\u003eamount != 1\")\n */\nclass Foo extends FooParent\n{\n    \n}\n\n/**\n * @Contract\\Invariant(\"$this-\u003eamount != 2\")\n */\nclass FooParent\n{\n    /**\n     * @var int\n     */\n    protected $amount;\n    \n    /**\n     * @param int $amount\n     */\n    protected function setBar($amount)\n    {\n        $this-\u003eamount = $amount;\n    }\n}\n    \n```\n\n`Foo::setBar` does not accept `1` and `2` literals as a parameter.\n\nIf you don't want to provide a contract on your curent method/class you can use the `Inherit` annotation:\n\n```php\nclass Foo extends FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Inherit\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n    \nclass FooParent\n{\n    /**\n     * @param int $amount\n     * @Contract\\Verify(\"$amount != 2\")\n     */\n    public function bar($amount)\n    {\n        ...\n    }\n}\n```\n\n`Foo:bar()` does accept eveything, except: `2`\n\nIntegration with assertion library\n----------\n\nTo enhance capabilities of contracts, it's possible to use [assertion library](https://github.com/beberlei/assert).\n```php\n    /**\n     * Deposits fixed amount of money to the account\n     *\n     * @param float $amount\n     *\n     * @Contract\\Ensure(\"Assert\\Assertion::integer($this-\u003ebalance)\")\n     */\n    public function deposit($amount)\n    {\n        $this-\u003ebalance += $amount;\n    }\n```\n\n[More assertions](https://github.com/beberlei/assert#list-of-assertions)\n\nIDE Integration\n---------------\nTo improve your productivity with PhpStorm, you should definitely install a [Go! AOP Framework](https://plugins.jetbrains.com/plugin/7785) plugin (\u003e=1.0.1) to have a PHP syntax highlighting for defining contracts and navigation to AOP advices.\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/640114/14225436/fc3e63a8-f8d3-11e5-9131-5c2ecc84ef60.png\" alt=\"PhpStorm example\" width=\"500px\" /\u003e\n\n\nCommon issues\n-----------\n\n##### Fatal error: Uncaught Error: Class 'Go\\ParserReflection\\Instrument\\PathResolver'\n```php\nFatal error: Uncaught Error: Class 'Go\\ParserReflection\\Instrument\\PathResolver' \nnot found in .../vendor/goaop/parser-reflection/src/ReflectionEngine.php on line XXX\n```\n\nThis happens if your `appDir` configuration points at the same level as your `vendor` directory.\nTo solve this issue try adding your `vendor` folder into the `excludePaths` configuration.\n\n```php\nContractApplication::getInstance()-\u003einit(array(\n    'debug'    =\u003e true,\n    'appDir'   =\u003e __DIR__,,\n    'excludePaths' =\u003e [\n        __DIR__ . '/vendor'\n    ],\n    'cacheDir' =\u003e __DIR__.'/cache/',\n));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-deal%2Fframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphp-deal%2Fframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-deal%2Fframework/lists"}