How the cyclomatic complexity of PHP open source software evolved over time - one line per release, measured with phploc.

Repositories
809
Releases
20,192
Lines of code
2,194,613,102
Average complexity
↓ −2.2%

Ø 9.73 → 9.51 across 791 libraries since January 1, 2026

Find or add a repository

Everything the report carries, plus every public repository on GitHub that is mostly written in PHP - a composer.json is not needed.

Rankings

Most starred repositories

The order the report itself is built around - stars decide what the chart opens with.

Open the chart
01 coollabsio

coolify

An open-source, self-hostable PaaS alternative to Vercel, Heroku & Netlify that lets you easily deploy static sites, databases, full-stack applications and 280+ one-click services on your own servers.

60.1k 17.36 since 2021→ ±0.0%
02 nextcloud

server

☁️ Nextcloud server, a safe home for all your data

36.3k 8.43 since 2010↓ −82.6%
03 laravel

framework

Laravel is a web application framework with expressive, elegant syntax.

34.8k 4.36 since 2013↑ +20.6%
04 filamentphp

filament

A powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire

31.7k 5.32 since 2020↑ +141.0%
05 symfony

symfony

The Symfony PHP framework

31.1k 6.54 since 2011↑ +25.3%
06 composer

composer

Dependency Manager for PHP

29.5k 20.90 since 2016↑ +56.8%
07 bagisto

bagisto

Free and open source laravel eCommerce platform

27.9k 4.53 since 2018↑ +41.1%
08 fzaninotto

Faker

Faker is a PHP library that generates fake data for you

26.7k 2.53 since 2012↓ −24.8%
09 monicahq

monica

Personal CRM. Remember everything about your friends, family and business relationships.

24.9k 3.29 since 2017↑ +22.0%

Complexity levels

1–10 Simple procedure, little risk
11–20 More complex, moderate risk
21–50 Complex, high risk
> 50 Untestable code, very high risk

How the report is made

Anyone can submit a repository - github.com is the only source, and no composer.json is needed. A submission is turned down when the repository is unknown, a fork, empty, larger than 10 GB, or less than 20% PHP by the language breakdown github.com reports for it; everything else is queued for a worker.

The worker clones it and checks out its release tags one after another. Only major and minor releases are measured (5.4, 5.4.0) - patch releases and pre-releases (anything carrying a -) are skipped, as are a handful of releases whose date git cannot tell straight. On every checkout, phploc reads every .php file of the working copy and leaves two numbers behind: lines of code, and the average cyclomatic complexity of a class, dated by the last commit that tag points at. The clone is deleted afterwards, the numbers stay.

From then on the report keeps itself current: every night it refreshes stars and asks github.com which releases are missing, so a new minor turns up in the chart by itself - and a repository that did not release is not even cloned.

About cyclomatic complexity

Cyclomatic complexity counts the paths through a piece of code: one, plus one for every branch - if, case, while, for, catch, &&, ||. Code without a single condition scores 1. What is charted here is the average over all classes of a release, so it says how branchy the average class of a library is - not how large it is, and not how good it is.

It is one metric, and worth what a metric is worth. It travels well as a rough measure of how many paths a test suite has to cover, and badly as a verdict: a clear class holding one big match outscores a tangle of indirection nobody can follow, and pushing branches into polymorphism lowers the figure without lowering the thinking. The shape of a line over the years says more than any point on it.

The data has its glitches, too. Whatever sits in a repository at a tag is measured, so committed dependencies, generated code and test suites count towards the average. Libraries that were split, renamed or imported from another version control system - Zend → Laminas, the early PHPUnit tags - carry dates and jumps their git history cannot explain. And a gap in a line is a release that was left out or could not be measured - not one that never happened.

By owner symfony sebastianbergmann doctrine laravel thephpleague spatie php-fig composer nextcloud PHPOffice phpDocumentor guzzle WordPress fruitcake matomo-org flarum Seldaek nikic barryvdh roots yiisoft aimeos phpstan DenverCoder1 reactphp phar-io dompdf ramsey paragonie cakephp googleapis bobthecow nunomaduro JakubOnderka pestphp api-platform kalcaddle openai-php php-http lcobucci Ocramius overtrue facebookarchive laminas antonioribeiro getsentry MarkBaker nette PHPCSStandards clue CarbonPHP typo3 eliashaeussler

Recently submitted

Latest additions