PHPackages                             dg/bypass-finals - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. dg/bypass-finals

ActiveLibrary[Testing &amp; Quality](/categories/testing)

dg/bypass-finals
================

Removes final keyword from source code on-the-fly and allows mocking of final methods and classes

v1.10.2(2w ago)57129.2M↓47.1%3420BSD-3-ClausePHPPHP &gt;=7.1CI failing

Since Sep 13Pushed 2w ago12 watchersCompare

[ Source](https://github.com/dg/bypass-finals)[ Packagist](https://packagist.org/packages/dg/bypass-finals)[ RSS](/packages/dg-bypass-finals/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (10)Dependencies (4)Versions (23)Used By (20)

[![bypass-finals](https://private-user-images.githubusercontent.com/194960/331425348-b299faba-77ee-41ac-8cb7-a482318dcacd.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODI5MDk2NDMsIm5iZiI6MTc4MjkwOTM0MywicGF0aCI6Ii8xOTQ5NjAvMzMxNDI1MzQ4LWIyOTlmYWJhLTc3ZWUtNDFhYy04Y2I3LWE0ODIzMThkY2FjZC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwNzAxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDcwMVQxMjM1NDNaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT01OTMyNmNjYmUyZmQ1YWMwNWVmOGViZWU5OTllMzUwM2ZlMGYyMWI0ODllYjZjYjhkODZlYzc5ODgwYzFhZmUzJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.WnQl7wAEqz3O7mICfDEFxJCgFfgcDRmDkT8iim8dAIY)](https://phpfashion.com/en/how-to-mock-final-classes)

[![Downloads this Month](https://camo.githubusercontent.com/639984385bfde653963d852f93edcd227364229a5317796bc8bde3e5a01b1229/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f64672f6279706173732d66696e616c732e737667)](https://packagist.org/packages/dg/bypass-finals)[![Tests](https://github.com/dg/bypass-finals/workflows/Tests/badge.svg?branch=master)](https://github.com/dg/bypass-finals/actions)[![Latest Stable Version](https://camo.githubusercontent.com/3f386722ce5ee424f065806b36cabe3c2a0d49aeab831bcf104043750a714a90/68747470733a2f2f706f7365722e707567782e6f72672f64672f6279706173732d66696e616c732f762f737461626c65)](https://github.com/dg/bypass-finals/releases)[![License](https://camo.githubusercontent.com/fa7d5fcf2c84b580327af52da95dd751703af65f079dc3c5a0081beac0789718/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4e65772532304253442d626c75652e737667)](https://github.com/dg/bypass-finals/blob/master/license.md)

Introduction
------------

[](#introduction)

**BypassFinals** effortlessly strips away `final` and `readonly` keywords from your PHP code on-the-fly. This handy tool makes it possible to mock final methods and classes, seamlessly integrating with popular testing frameworks like PHPUnit, Mockery, or [Nette Tester](https://tester.nette.org).

Installation
------------

[](#installation)

The easiest way to install BypassFinals is via Composer. Just run the following command in your project directory:

```
composer require dg/bypass-finals --dev

```

Usage
-----

[](#usage)

To get BypassFinals up and running, just invoke:

```
DG\BypassFinals::enable();
```

Make sure to call this method early, preferably immediately after your `vendor/autoload.php` is loaded, to ensure all classes are processed before they are used.

Note that final internal PHP classes like `Closure` are not mockable.

To avoid removing `readonly` keywords, you can disable this feature by passing a parameter:

```
DG\BypassFinals::enable(bypassReadOnly: false);
```

To narrow down the application scope of BypassFinals, use a whitelist to specify directories or files:

```
DG\BypassFinals::allowPaths([
	'*/Nette/*',
]);
```

Or, conversely, you can specify which paths not to search using `DG\BypassFinals::denyPaths()`. This gives you finer control and can solve issues with certain frameworks and libraries.

Enhance performance by caching transformed files. Make sure the cache directory already exists:

```
DG\BypassFinals::setCacheDirectory(__DIR__ . '/cache');
```

For integration with PHPUnit 10 or newer, simply add BypassFinals as an extension in your PHPUnit XML configuration file:

```

```

Optionally you can configure BypassFinals in your `phpunit.xml` file:

```

```

Troubleshooting
---------------

[](#troubleshooting)

**Class is still final after enabling BypassFinals**

BypassFinals can only strip the `final` keyword from files loaded *after* `enable()` is called. If a class is loaded before that — for example via a `files` entry in a package's `autoload` configuration, which Composer loads during `require 'vendor/autoload.php'` — the class will remain final.

To handle this, include `src/bootstrap.php` *before* `vendor/autoload.php` in your test bootstrap file:

```
// tests/bootstrap.php
require __DIR__ . '/../vendor/dg/bypass-finals/src/bootstrap.php';
require __DIR__ . '/../vendor/autoload.php';
```

This activates the stream wrapper early enough to intercept every file loaded during autoloading.

If you encounter other 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:

```
DG\BypassFinals::debugInfo();
```

This will display:

- Configuration: Whether BypassFinals is enabled for removing `final` and/or `readonly` keywords.
- BypassFinals startup call stack: The sequence of function calls that led to `DG\BypassFinals::enable()`, helping you verify when and where BypassFinals was started.
- 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.
- 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.

By 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.

Do you like this project?
-------------------------

[](#do-you-like-this-project)

Check out my other innovative open-source projects that might catch your interest:

✅ [Latte](https://latte.nette.org): The only safe and intuitive templating system for PHP
✅ [Tracy](https://tracy.nette.org): An addictive debugging tool to enhance your development workflow
✅ [PhpGenerator](https://doc.nette.org/en/php-generator): A robust library for generating PHP code with modern features
✅ [Nette Framework](https://nette.org): A thoughtfully engineered and popular web framework.

[](#-latte-the-only-safe-and-intuitive-templating-system-for-php-tracy-an-addictive-debugging-tool-to-enhance-your-development-workflow-phpgenerator-a-robust-library-for-generating-php-code-with-modern-features-nette-framework-a-thoughtfully-engineered-and-popular-web-framework)

Support Project
---------------

[](#support-project)

[![Donate](https://camo.githubusercontent.com/2dd1529e9dabe93bc54843d8f07c6089790b57f1357f23af1c108fb09f3c1de0/68747470733a2f2f66696c65732e6e657474652e6f72672f69636f6e732f646f6e6174696f6e2d312e7376673f)](https://nette.org/make-donation?to=bypass-finals)

###  Health Score

73

—

ExcellentBetter than 100% of packages

Maintenance96

Actively maintained with recent releases

Popularity70

Solid adoption and visibility

Community49

Growing community involvement

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 78.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~152 days

Recently: every ~178 days

Total

22

Last Release

18d ago

PHP version history (2 changes)v1.0PHP &gt;=5.6

v1.2.0PHP &gt;=7.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/17f266513a3ca97500ec3d85d562b9279c7a6346358fe2b8d90390ece717a027?d=identicon)[david@grudl.com](/maintainers/david@grudl.com)

---

Top Contributors

[![dg](https://avatars.githubusercontent.com/u/194960?v=4)](https://github.com/dg "dg (85 commits)")[![guillaumedelre](https://avatars.githubusercontent.com/u/2004182?v=4)](https://github.com/guillaumedelre "guillaumedelre (4 commits)")[![phcorp](https://avatars.githubusercontent.com/u/725023?v=4)](https://github.com/phcorp "phcorp (2 commits)")[![dmitryuk](https://avatars.githubusercontent.com/u/661654?v=4)](https://github.com/dmitryuk "dmitryuk (2 commits)")[![Nyholm](https://avatars.githubusercontent.com/u/1275206?v=4)](https://github.com/Nyholm "Nyholm (2 commits)")[![fancsali](https://avatars.githubusercontent.com/u/1670136?v=4)](https://github.com/fancsali "fancsali (1 commits)")[![jorgsowa](https://avatars.githubusercontent.com/u/74921107?v=4)](https://github.com/jorgsowa "jorgsowa (1 commits)")[![milo](https://avatars.githubusercontent.com/u/439140?v=4)](https://github.com/milo "milo (1 commits)")[![nightlinus](https://avatars.githubusercontent.com/u/2681887?v=4)](https://github.com/nightlinus "nightlinus (1 commits)")[![oruborus](https://avatars.githubusercontent.com/u/17663?v=4)](https://github.com/oruborus "oruborus (1 commits)")[![SanderMuller](https://avatars.githubusercontent.com/u/9074391?v=4)](https://github.com/SanderMuller "SanderMuller (1 commits)")[![sanmai](https://avatars.githubusercontent.com/u/139488?v=4)](https://github.com/sanmai "sanmai (1 commits)")[![afilina](https://avatars.githubusercontent.com/u/199835?v=4)](https://github.com/afilina "afilina (1 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (1 commits)")[![Ammarpad](https://avatars.githubusercontent.com/u/45658045?v=4)](https://github.com/Ammarpad "Ammarpad (1 commits)")[![bzikarsky](https://avatars.githubusercontent.com/u/225374?v=4)](https://github.com/bzikarsky "bzikarsky (1 commits)")[![danog](https://avatars.githubusercontent.com/u/7339644?v=4)](https://github.com/danog "danog (1 commits)")[![Eli-Caraballo](https://avatars.githubusercontent.com/u/59987371?v=4)](https://github.com/Eli-Caraballo "Eli-Caraballo (1 commits)")

---

Tags

file-mutatormockingphpunittestingtestingphpunitunitmockingfinals

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/dg-bypass-finals/health.svg)

```
[![Health](https://phpackages.com/badges/dg-bypass-finals/health.svg)](https://phpackages.com/packages/dg-bypass-finals)
```

###  Alternatives

[nette/tester

Nette Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏

4957.6M1.7k](/packages/nette-tester)[elliotchance/concise

Concise is test framework for using plain English and minimal code, built on PHPUnit.

47224.2k4](/packages/elliotchance-concise)[janmarek/mockista

Mockista is library for mocking, which I've written, because I find mocking in PHPUnit awful.

29222.1k28](/packages/janmarek-mockista)[tcz/phpunit-mockfunction

PHPUnit extension that uses runkit to mock PHP functions (both user-defined and system)

4950.4k2](/packages/tcz-phpunit-mockfunction)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
