brianhenryie / strauss
Prefixes dependencies namespaces so they are unique to your plugin
Installs: 227 861
Dependents: 9
Suggesters: 0
Security: 0
Stars: 172
Watchers: 3
Forks: 59
Open Issues: 35
pkg:composer/brianhenryie/strauss
Requires
- composer-runtime-api: ^2.0
- brianhenryie/simple-php-code-parser: ^0.15.3
- composer/class-map-generator: ^1.6.0
- composer/composer: ^2.6.0
- elazar/flystream: ^0.5.0|^1
- json-mapper/json-mapper: ^2.0.0
- league/flysystem: ^2.1|^3.0
- league/flysystem-memory: *
- monolog/monolog: ^2.10
- nikic/php-parser: ^5.4.0
- symfony/console: ^4|^5|^6|^7
- symfony/finder: ^4|^5|^6|^7
Requires (Dev)
- php: ^7.4|^8.0
- ext-json: *
- brianhenryie/color-logger: ^1.2
- clue/phar-composer: ^1.2
- jaschilz/php-coverage-badger: ^2.0
- mheap/phpunit-github-actions-printer: ^1.4
- mockery/mockery: ^1.6
- phpstan/phpstan: ^1.10
- phpunit/phpcov: *
- phpunit/phpunit: ^9|^10
- squizlabs/php_codesniffer: ^3.5
Conflicts
- json-mapper/json-mapper: 2.23.0 | 2.24.0
Replaces
- dev-master
- 0.24.1
- 0.24.0
- 0.23.0
- 0.22.6
- 0.22.5
- 0.22.4
- 0.22.3
- 0.22.2
- 0.22.1
- 0.22.0
- 0.21.1
- 0.21.0
- 0.20.1
- 0.20.0
- 0.19.5
- 0.19.4
- 0.19.3
- 0.19.2
- 0.19.1
- 0.19.0
- 0.18.0
- 0.17.0
- 0.16.0
- 0.15.0
- 0.14.1
- 0.14.0
- 0.13.0
- 0.12.0
- 0.11.1
- 0.11.0
- 0.10.4
- 0.10.3
- 0.10.2
- 0.10.1
- 0.10.0
- 0.9.0
- 0.8.10
- 0.8.9
- 0.8.8
- 0.8.7
- 0.8.6
- 0.8.5
- 0.8.4
- 0.8.3
- 0.8.2
- 0.8.1
- 0.8.0
- 0.5.0
- 0.4.0
- 0.3.0
- 0.2.2
- 0.2.0
- 0.1.0
- dev-fix-207-215-file-copy
- dev-add/SymlinkProtectFileSystem
- dev-fix-files-autoloader-require-twice
- dev-fix-208-files-aliases
- dev-fix-cleanup-after-delete-vendor-packages
- dev-fix-204-strauss-doesnt-read-custom-config
- dev-fix/prefix-contants
- dev-add/monolog
- dev-fix-190
- dev-fix-vendor-autoloader
- dev-update-dependency
- dev-fix-psr4-autoloader-189
- dev-add/189-test
- dev-add/188-tests
- dev-fix/191
- dev-fix/183
- dev-fix/166
- dev-fix/179
- dev-fix/173
- dev-patch-1
- dev-fix/171
- dev-fix/close-mockery
- dev-Add-`ComposerAutoloadGenerator`
- dev-typos-again
- dev-fix/163
- dev-fix/154
- dev-fix/remove-duplicated-silent-option
- dev-fix/159
- dev-fix/136-do-not-update-call-sites
- dev-add/alias-renamed-classes-for-dev-dependencies
- dev-issue92-plain-version
This package is auto-updated.
Last update: 2025-10-22 03:47:26 UTC
README
Strauss – PHP Namespace Renamer
A tool to prefix namespaces, classnames, and constants in PHP files to avoid autoloading collisions.
A fork of Mozart for Composer for PHP.
Have you ever activated a WordPress plugin that has a conflict with another because the plugins use two different versions of the same PHP library? Strauss is the solution to that problem - it ensures that your plugin's PHP dependencies are isolated and loaded from your plugin rather than loading from whichever plugin's autoloader registers & runs first.
⚠️ Sponsorship: It would be neat if you were to offer me a license to your plugin, or at least post about where this is used.
Table of Contents
- Installation
- As a
.pharfile (recommended) - As a dev dependency via composer (not recommended)
- Edit
composer.jsonscripts
- As a
- Usage
- Configuration
- Autoloading
- Motivation & Comparison to Mozart
- Alternatives
- Breaking Changes
- Acknowledgements
Installation
As a .phar file (recommended)
There are a couple of small steps to make this possible.
Create a bin/.gitkeep file
This ensures that there is a bin/ directory in the root of your project. This is where the .phar file will go.
mkdir bin touch bin/.gitkeep
.gitignore the .phar file
Add the following to your .gitignore:
bin/strauss.phar
Edit composer.json `scripts
In your composer.json, add strauss to the scripts section:
"scripts": { "prefix-namespaces": [ "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/latest/download/strauss.phar'", "@php bin/strauss.phar", "@composer dump-autoload" ], "post-install-cmd": [ "@prefix-namespaces" ], "post-update-cmd": [ "@prefix-namespaces" ], "post-autoload-dump": [ "@php bin/strauss.phar include-autoloader" ] }
This provides composer strauss, which does the following:
- The
sh -ccommand tests ifbin/strauss.pharexists, and if not, downloads it from releases. - Then
@php bin/strauss.pharis run to prefix the namespaces. - Ensure that composer's autoload map is updated.
As a dev dependency via composer (not recommended)
If you prefer to include Strauss as a dev dependency, you can still do so. You mileage may vary when you include it this way.
composer require --dev brianhenryie/strauss
Edit composer.json `scripts
"scripts": { "prefix-namespaces": [ "strauss", "@php composer dump-autoload" ], "post-install-cmd": [ "@prefix-namespaces" ], "post-update-cmd": [ "@prefix-namespaces" ], "post-autoload-dump": [ "strauss include-autoloader" ] }
Usage
If you add Strauss to your composer.json as indicated in Installation, it will run when you composer install or composer update. To run Strauss directly, simply use:
composer prefix-namespaces
To update the files that call the prefixed classes, you can use --updateCallSites=true which uses your autoload key, or --updateCallSites=includes,templates to explicitly specify the files and directories.
composer -- prefix-namespaces --updateCallSites=true
or
composer -- prefix-namespaces --updateCallSites=includes,templates
To try it out without making changes, you can use the --dry-run flag:
Verbosity can be controlled with --notice (default), --info, --debug and --silent.
Configuration
Strauss potentially requires zero configuration, but likely you'll want to customize a little, by adding in your composer.json an extra/strauss object. The following is the default config, where the namespace_prefix and classmap_prefix are determined from your composer.json's autoload or name key and packages is determined from the require key:
"extra": { "strauss": { "target_directory": "vendor-prefixed", "namespace_prefix": "BrianHenryIE\\My_Project\\", "classmap_prefix": "BrianHenryIE_My_Project_", "constant_prefix": "BHMP_", "packages": [ ], "update_call_sites": false, "override_autoload": { }, "exclude_from_copy": { "packages": [ ], "namespaces": [ ], "file_patterns": [ ] }, "exclude_from_prefix": { "packages": [ ], "namespaces": [ ], "file_patterns": [ ] }, "namespace_replacement_patterns" : { }, "delete_vendor_packages": false, "delete_vendor_files": false } },
The following configuration is inferred:
target_directorydefines the directory the files will be copied to, defaultvendor-prefixednamespace_prefixdefines the default string to prefix each namespace withclassmap_prefixdefines the default string to prefix class names in the global namespacepackagesis the list of packages to process. If absent, all packages in therequirekey of yourcomposer.jsonare includedclassmap_outputis aboolto decide if Strauss will createautoload-classmap.phpandautoload.php. If it is not set, it isfalseiftarget_directoryis in your project'sautoloadkey,trueotherwise.
The following configuration is default:
delete_vendor_packages:falsea boolean flag to indicate if the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in.delete_vendor_files:falsea boolean flag to indicate if files copied from the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in. This is maybe deprecated! Is there any use to this that is more appropriate thandelete_vendor_packages?include_modified_dateis aboolto decide if Strauss should include a date in the (phpdoc) header written to modified files. Defaults totrue.include_authoris aboolto decide if Strauss should include the author name in the (phpdoc) header written to modified files. Defaults totrue.update_call_sites:false. This can betrue,falseor anarrayof directories/filepaths. When set totrueit defaults to the directories and files in the project'sautoloadkey. The PHP files and directories' PHP files will be updated where they call the prefixed classes.
The remainder is empty:
constant_prefixis fordefine( "A_CONSTANT", value );->define( "MY_PREFIX_A_CONSTANT", value );. If it is empty, constants are not prefixed (this may change to an inferred value).override_autoloada dictionary, keyed with the package names, of autoload settings to replace those in the original packages'composer.jsonautoloadproperty.exclude_from_prefix/file_patternsexclude_from_copypackagesarray of package names to be skippednamespacesarray of namespaces to skip (exact match from the package autoload keys)file_patternsarray of regex patterns to check filenames against (including vendor relative path) where Strauss will skip that file if there is a match
exclude_from_prefixpackagesarray of package names to exclude from prefixing.namespacesarray of exact match namespaces to exclude (i.e. not substring/parent namespaces)
namespace_replacement_patternsa dictionary to use inpreg_replaceinstead of prefixing withnamespace_prefix.
Autoloading
Strauss uses Composer's own tools to generate a set of autoload files in the target_directory and creates an autoload.php alongside it, so in many projects autoloading is just a matter of:
require_once __DIR__ . '/vendor-prefixed/autoload.php';
If you plan to continue using Composer's autoloader you probably want to turn on delete_vendor_packages or set target_directory to vendor.
You can use strauss include-autoloader to add a line to vendor/autoload.php which includes the autoloader for the new files.
When delete_vendor_packages is enabled, vendor/composer/autoload_aliases.php is created to allow modified classes to be loaded with their old name during development. This file should not be included in your production code.
Motivation & Comparison to Mozart
I was happy to make PRs to Mozart to fix bugs, but they weren't being reviewed and merged. At the time of writing, somewhere approaching 50% of Mozart's code was written by me with an additional nine open PRs and the majority of issues' solutions provided by me. This fork is a means to merge all outstanding bugfixes I've written and make some more drastic changes I see as a better approach to the problem.
Benefits over Mozart:
- A single output directory whose structure matches source vendor directory structure (conceptually easier than Mozart's independent
classmap_directoryanddep_directory) - A generated
autoload.phptoincludein your project (analogous to Composer'svendor/autoload.php) - Handles
filesautoloaders – and any autoloaders that Composer itself recognises, since Strauss uses Composer's own tooling to parse the packages - Zero configuration – Strauss infers sensible defaults from your
composer.json - No destructive defaults –
delete_vendor_filesdefaults tofalse, so any destruction is explicitly opt-in - Licence files are included and PHP file headers are edited to adhere to licence requirements around modifications. My understanding is that re-distributing code that Mozart has handled is non-compliant with most open source licences – illegal!
- Extensively tested – PhpUnit tests have been written to validate that many of Mozart's bugs are not present in Strauss
- More configuration options – allowing exclusions in copying and editing files, and allowing specific/multiple namespace renaming
- Respects
composer.jsonvendor-dirconfiguration - Prefixes constants (
define) - Handles meta-packages and virtual-packages
Strauss will read the Mozart configuration from your composer.json to enable a seamless migration.
Alternatives
I don't have a strong opinion on these. I began using Mozart because it was easy, then I adapted it to what I felt was most natural. I've never used these.
- humbug/php-scoper
- TypistTech/imposter-plugin
- Automattic/jetpack-autoloader
- tschallacka/wordpress-composer-plugin-builder
- Interfacelab/namespacer
- PHP-Prefixer SaaS!
Interesting
- composer-unused/composer-unused
- sdrobov/autopsr4
- jaem3l/unfuck
- bamarni/composer-bin-plugin
- phar-io/composer-distributor
Breaking Changes
- v0.21.0 – will prefix global functions
- v0.16.0 – will no longer prefix PHP built-in classes seen in polyfill packages
- v0.14.0 –
psr/*packages no longer excluded by default - v0.12.0 – default output
target_directorychanges fromstrausstovendor-prefixed
Please open issues to suggest possible breaking changes. I think we can probably move to 1.0.0 soon.
Backward Compatibility Promise
This project will not increase its minimum required PHP version ahead of WordPress.
https://core.trac.wordpress.org/ticket/62622
Changes before v1.0
- Comprehensive attribution of code forked from Mozart – changes have been drastic and
git blameis now useless, so I intend to add more attributions - More consistent naming. Are we prefixing or are we renaming?
- Further unit tests, particularly file-system related
- Regex patterns in config need to be validated
- Change the name? "Renamespacer"?
Changes before v2.0
The correct approach to this problem is probably via PHP-Parser. At least all the tests will be useful.
Acknowledgements
Coen Jacobs and all the contributors to Mozart, particularly those who wrote nice issues.