{"id":15014430,"url":"https://github.com/dg/bypass-finals","last_synced_at":"2025-10-05T21:32:24.716Z","repository":{"id":38863716,"uuid":"103428603","full_name":"dg/bypass-finals","owner":"dg","description":"Removes `final` and `readonly` keywords from source code on-the-fly and allows mocking of final methods and classes. It can be used together with any test tool such as PHPUnit or Mockery.","archived":false,"fork":false,"pushed_at":"2025-03-30T17:41:34.000Z","size":64,"stargazers_count":520,"open_issues_count":7,"forks_count":32,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-03T04:39:44.171Z","etag":null,"topics":["file-mutator","mocking","phpunit","testing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dg.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"dg"}},"created_at":"2017-09-13T17:14:20.000Z","updated_at":"2025-04-25T12:08:20.000Z","dependencies_parsed_at":"2022-07-08T03:10:30.238Z","dependency_job_id":"0ecb3dfe-c206-440f-bad4-579785b11d5b","html_url":"https://github.com/dg/bypass-finals","commit_stats":{"total_commits":78,"total_committers":15,"mean_commits":5.2,"dds":"0.20512820512820518","last_synced_commit":"86b00f0d900c7e15d3341e687e0df89e8c2d4632"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dg%2Fbypass-finals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dg%2Fbypass-finals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dg%2Fbypass-finals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dg%2Fbypass-finals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dg","download_url":"https://codeload.github.com/dg/bypass-finals/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252422843,"owners_count":21745503,"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":["file-mutator","mocking","phpunit","testing"],"created_at":"2024-09-24T19:45:37.496Z","updated_at":"2025-10-05T21:32:19.677Z","avatar_url":"https://github.com/dg.png","language":"PHP","funding_links":["https://github.com/sponsors/dg"],"categories":["PHP"],"sub_categories":[],"readme":"[![bypass-finals](https://github.com/dg/bypass-finals/assets/194960/b299faba-77ee-41ac-8cb7-a482318dcacd)](https://phpfashion.com/en/how-to-mock-final-classes)\n\n[![Downloads this Month](https://img.shields.io/packagist/dm/dg/bypass-finals.svg)](https://packagist.org/packages/dg/bypass-finals)\n[![Tests](https://github.com/dg/bypass-finals/workflows/Tests/badge.svg?branch=master)](https://github.com/dg/bypass-finals/actions)\n[![Latest Stable Version](https://poser.pugx.org/dg/bypass-finals/v/stable)](https://github.com/dg/bypass-finals/releases)\n[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/dg/bypass-finals/blob/master/license.md)\n\n \u003c!----\u003e\n\nIntroduction\n------------\n\n**BypassFinals** effortlessly strips away `final` and `readonly` keywords from your PHP code on-the-fly.\nThis handy tool makes it possible to mock final methods and classes, seamlessly integrating with popular\ntesting frameworks like PHPUnit, Mockery, or [Nette Tester](https://tester.nette.org).\n\n \u003c!----\u003e\n\nInstallation\n------------\n\nThe easiest way to install BypassFinals is via Composer. Just run the following command in your project directory:\n\n```\ncomposer require dg/bypass-finals --dev\n```\n\nIt pretty much runs everywhere: PHP 7.1 through 8.4 are all supported!\n\n \u003c!----\u003e\n\nUsage\n-----\n\nTo get BypassFinals up and running, just invoke:\n\n```php\nDG\\BypassFinals::enable();\n```\n\nMake sure to call this method early, preferably immediately after your `vendor/autoload.php` is loaded,\nto ensure all classes are processed before they are used.\n\nNote that final internal PHP classes like `Closure` are not mockable.\n\nTo avoid removing `readonly` keywords, you can disable this feature by passing a parameter:\n\n```php\nDG\\BypassFinals::enable(bypassReadOnly: false);\n```\n\nTo narrow down the application scope of BypassFinals, use a whitelist to specify directories or files:\n\n```php\nDG\\BypassFinals::allowPaths([\n\t'*/Nette/*',\n]);\n```\n\nOr, conversely, you can specify which paths not to search using `DG\\BypassFinals::denyPaths()`.\nThis gives you finer control and can solve issues with certain frameworks and libraries.\n\nEnhance performance by caching transformed files. Make sure the cache directory already exists:\n\n```php\nDG\\BypassFinals::setCacheDirectory(__DIR__ . '/cache');\n```\n\nFor integration with PHPUnit 10 or newer, simply add BypassFinals as an extension in your PHPUnit XML configuration file:\n\n```xml\n\u003cextensions\u003e\n\t\u003cbootstrap class=\"DG\\BypassFinals\\PHPUnitExtension\"/\u003e\n\u003c/extensions\u003e\n```\n\nOptionally you can configure BypassFinals in your `phpunit.xml` file:\n\n```xml\n\u003cextensions\u003e\n\t\u003cbootstrap class=\"DG\\BypassFinals\\PHPUnitExtension\"\u003e\n\t\t\u003cparameter name=\"bypassFinal\" value=\"true\"/\u003e\n\t\t\u003cparameter name=\"bypassReadOnly\" value=\"false\"/\u003e\n\t\t\u003cparameter name=\"cacheDirectory\" value=\"./cache\"/\u003e\n\t\u003c/bootstrap\u003e\n\u003c/extensions\u003e\n```\n\n \u003c!----\u003e\n\nTroubleshooting\n---------------\n\nIf you encounter issues with BypassFinals not working as expected, you can use the `debugInfo()` method to gain insights into its internal state. Calling this method will output valuable information to help diagnose the problem:\n\n```php\nDG\\BypassFinals::debugInfo();\n```\n\nThis will display:\n\n- Configuration: Whether BypassFinals is enabled for removing `final` and/or `readonly` keywords.\n- BypassFinals startup call stack: The sequence of function calls that led to `DG\\BypassFinals::enable()`, helping you verify when and where BypassFinals was started.\n- Classes loaded before BypassFinals startup: A list of classes that were already loaded in PHP before BypassFinals was started. Keywords in these classes cannot be removed, as the classes are already defined. This can help identify potential conflicts or reasons why certain classes aren't being modified.\n- Modified files: A list of the files that BypassFinals has successfully modified. If the file containing a class you expect to be modified isn't in this list, it suggests a problem with path matching or the timing of the BypassFinals startup.\n\nBy examining this output, you can better understand how BypassFinals is configured and whether it's operating on the intended files and classes. This can significantly speed up the process of identifying and resolving issues.\n\n \u003c!----\u003e\n\nDo you like this project?\n---------\n\nCheck out my other innovative open-source projects that might catch your interest:\n\n\u003ch3\u003e\n\n✅ [Latte](https://latte.nette.org): The only safe and intuitive templating system for PHP\u003cbr\u003e\n✅ [Tracy](https://tracy.nette.org): An addictive debugging tool to enhance your development workflow\u003cbr\u003e\n✅ [PhpGenerator](https://doc.nette.org/en/php-generator): A robust library for generating PHP code with modern features\u003cbr\u003e\n✅ [Nette Framework](https://nette.org): A thoughtfully engineered and popular web framework.\u003cbr\u003e\n\n\u003c/h3\u003e\n\n \u003c!----\u003e\n\nSupport Project\n---------------\n\n[![Donate](https://files.nette.org/icons/donation-1.svg?)](https://nette.org/make-donation?to=bypass-finals)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdg%2Fbypass-finals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdg%2Fbypass-finals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdg%2Fbypass-finals/lists"}