PHP developer FAQ
This page is for PHP developers who want a quick answer. Each answer links to the page with the details.
Warning
.htaccess slows down every request. When .htaccess files are enabled (AllowOverride anything but None), let alone
used, Apache looks for them and reads and evaluates them on every request, in every directory of the path, and
page loading times go up drastically (measured). The only real fix is to switch the feature off for
the virtual host: AllowOverride None in the HTTPS virtual host, and the rules in the virtual host's own
configuration as mod_rewrite rules. That is far faster in production speed tests and well worth the time it takes
to optimize a production configuration. Switch over right away: copy the rules of the
example HTTPS virtual host into your virtual host (with the static cache, also
staticcache_offload.conf), set AllowOverride None, run apachectl configtest, reload Apache and
test the site. The same rules for other servers: nginx, LiteSpeed,
Caddy, IIS, Velocity (built in); where virtual host rules go in a control
panel: Plesk, cPanel, DirectAdmin, ISPConfig.
On LiteSpeed or OpenLiteSpeed, the server's own page cache can also answer anonymous visitors and crawlers without PHP: Page caching with LiteSpeed and OpenLiteSpeed.
Contents
Platform and language
Which PHP versions must my code support? PHP 8.0 to 8.5 (PHP 7.4 usable without support). PHP 8.0 is the oldest because it is the stock PHP of RHEL 9 (Supported PHP versions: 8.0 to 8.5).
Can I use enums, readonly properties or foo(...)?
Not in code that ships with or for Exponential: PHP 8.0 cannot parse them
(Writing code that runs on PHP 8.0).
Why no declare( strict_types=1 ) and no return types?
The coding standard forbids them in new code, for consistency with the existing code, compatibility of subclasses and
PHP 8.0 (Why the code has no type declarations).
Why array() and not []?
The house style, measured on the existing code and checked by phpcs.xml.dist (The coding standard).
Does Exponential follow PSR-4 or PSR-12? No. Classes are found through generated class maps, and the code style is the kernel's own (PHP, PHP-FIG and Composer standards).
May I use namespaces?
Yes. The kernel uses them for commands, cronjob parts, views and services
(Exponential\Command\...); other classes are global with a prefix (Class naming and the exp prefix).
Is there a Symfony layer? Exponential 6 runs on its own kernel. The legacy bridge runs it inside a Symfony platform installation (Symfony and the legacy bridge).
What are the ezc* classes, and where do they come from?
They are the kernel's libraries (ezcMail, ezcArchive, ezcWebdavServer, ezcMvcController ...). Since 6.0.15
they come from the expcomponents (se7enxweb/expcomponents-*), Exponential's fork of the Zeta Components, under
the Apache License 2.0; the class names and APIs did not change. A bug in one of them goes to that fork's repository
(Exponential Components, Contributing to expcomponents).
My extension requires zetacomponents/mail. Must I change it?
No: each fork replaces its upstream name, so the requirement is met. Rename it to se7enxweb/expcomponents-mail in
your next release (Upgrade notes: the switch to expcomponents).
Classes and settings
My new class is "not found".
Run php bin/php/ezpgenerateautoloads.php -e; under Velocity also restart the workers (exp:velocity deploy)
(Autoloads and class maps).
I changed a setting and nothing happened.
Clear the INI cache with --clear-tag=ini (not --clear-id=ini), check the layer that wins with exp:ini where, and
restart Velocity's workers (Reading settings with eZINI).
How do I create .htaccess and config.php?
./console exp:setup:htaccess --apply and ./console exp:setup:config --apply copy them from .htaccess_root and
config.php-RECOMMENDED; an existing file that differs is shown as a diff and kept unless --force
(Setting up .htaccess and config.php from the console).
How do I change a config.php setting without an editor?
./console exp:config:set <NAME> <value> [--type=bool|int|octal|float|string|null] --apply. The file is read as PHP
tokens, never run; only the value of that one define() changes, and the result must pass php -l. A constant of your
own extension needs --allow-unknown. Under Velocity restart the workers afterwards
(Setting up .htaccess and config.php from the console).
Should I rename eZContentObject and the other eZ classes?
Never. They are real identifiers that every extension uses; new code uses exp or your own prefix.
How do I change one kernel view without copying it?
Subclass its class and register the subclass in site.ini [RunnableSettings] Implementation[]
(Module views as classes).
Velocity and deploys
My edit to a PHP file does nothing.
Under Velocity the workers keep loaded classes: exp:velocity deploy. With the engine archive on, a kernel edit needs a
rebuild, which the deploy does (The engine archive (phar) for PHP developers).
A page shows another user's or siteaccess's data, only under Velocity. State kept between requests: a function static, a cache keyed by too little, a register-once flag (Static state traps).
My download view prints the page after the file.
eZExecution::cleanExit() is inside a catch ( Exception ). Under Velocity it ends the request with an exception; do not
catch it (Velocity persistent workers for PHP developers).
Does FrankenPHP keep state between requests? No. It runs in classic mode, a clean state per request (FrankenPHP for PHP developers).
Databases
Which database should I develop on? SQLite 3 is the default and needs nothing; test on a server database too before you release (Code for every supported database).
How do I avoid SQL injection?
escapeString() for strings, (int) for numbers, or eZPersistentObject conditions (SQL with eZDB, safely).
My SQL returns nothing on MongoDB.
The adapter translates the kernel's SQL shapes only; untranslatable SQL returns an empty result and logs MONGO TODO.
Tests and CI
Do I need a database to run the tests?
No. vendor/bin/phpunit runs the DB-less suites; database tests run separately with tests/runtests.php --dsn ...
(PHPUnit without a database, Database and live tests).
PHPStan fails on code I did not touch.
Only findings missing from phpstan-baseline.neon fail; check whether your change moved or changed that code
(Static analysis with PHPStan).
CI is red but everything passes locally. Usually a test reads your installation's settings, or CI runs an older PHPUnit or PHP (CI and reproducing a red check).
The commit-msg hook refuses my commit.
Start the subject with Added: , Updated: , Fixed: , Removed: or Renamed:
(Git hooks and make targets).
Where to start
Read Exponential for PHP developers, set up a checkout, then do Write your first module view. The full order is The PHP developer's reading path.
Related pages
- PHP Developers: start here
- Application creators: frequently asked questions
- Software Engineers: start here, Web Framework Developers: start here, the extension developer book
- Glossary for PHP developers
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.