Releases: phalcon/cphalcon
Releases · phalcon/cphalcon
v5.14.2
5.14.2 (2026-06-12)
Tools
- Zephir Parser v2.0.4
- Zephir 0.23.0 (development - 27535f802)
Changed
- Changed
Phalcon\Cli\Console::handle()to process module definitions the same way asPhalcon\Mvc\Application::handle(). The module is now resolved through the inheritedgetModule(), so an unregistered module throwsPhalcon\Application\Exceptions\ModuleNotRegistered(asConsole::getModule()already did) instead ofPhalcon\Cli\Console\Exceptions\ConsoleModuleNotRegistered.Closuremodule definitions are now supported and are invoked with the container, matching MVC. A definition that is neither an array nor aClosurethrows the newPhalcon\Cli\Console\Exceptions\InvalidModuleDefinitioninstead ofInvalidModuleDefinitionPath. #17107 - Changed
Phalcon\Config\Adapter\Ini::parseIniString()to usePhalcon\Config\Config::DEFAULT_PATH_DELIMITERfor the key nesting separator instead of a hardcoded.(no behavior change). #17134 - Changed
Phalcon\Config\Adapter\JsonandPhalcon\Config\Adapter\Phpto throwPhalcon\Config\Exceptions\CannotLoadConfigFilewhen the configuration file cannot be read, instead of failing inside the JSON decoder (Json) or with a fatalrequireerror (Php). All file based Config adapters now share the same failure contract. #17134 - Changed
Phalcon\Config\ConfigFactoryto resolve adapter-specific constructor arguments (modeforini,callbacksforyaml) through a single internal parameter map consulted by bothload()andnewInstance(), instead of two hardcoded switches.load()now also resolves theymladapter name / file extension to theyamladapter. #17134 - Consolidated the
allowEmptyhandling ofPhalcon\Filter\Validationinto the validator (Phalcon\Filter\Validation\AbstractValidator::isAllowEmpty()). The per-fieldallowEmptymap is also honored. #17124 - Moved the resolution of an array
attributeoption fromPhalcon\Filter\Validation\AbstractValidator::getOption()intoPhalcon\Filter\Validation\Validator\Uniqueness::getOption(). #17124
Added
- Added
Phalcon\Filter\Filter::getDefaultMapper(), for mapper services used also byPhalcon\Filter\FilterFactory::getServices(). #17124 - Added
Phalcon\Filter\Validation\Validator\File\Resolution\AspectRatio, validating that an uploaded image has an exact aspect ratio. Theratiooption uses the16x9format (per-field array form supported) and is compared with integer cross-multiplication, so the dimensions must match exactly: 1920x1080 matches16x9, 1366x768 does not. Also available through the compositePhalcon\Filter\Validation\Validator\Filevia theaspectRatioandmessageAspectRatiooptions. #17104 - Added
SessionUpdateTimestampHandlerInterfacesupport to thePhalcon\Sessionadapters (Noop,Stream,Redis,Libmemcached), enabling PHP'ssession.lazy_write(on by default): when the session data is unchanged at close, PHP now callsupdateTimestamp()instead ofwrite().Streamtouches the session file without rewriting its data;RedisandLibmemcacheddelegate towrite()to refresh the TTL. Withsession.use_strict_modeenabled, the newvalidateId()rejects uninitialized session ids. #17129 - Added a
stripPrefixoption (defaulttrue) to thePhalcon\Storage/Phalcon\Cacheadapters, controlling whether a leading prefix is stripped from incoming keys (the behavior introduced for #17089).Phalcon\Session\Adapter\RedisandPhalcon\Session\Adapter\Libmemcacheddisable it by default: session ids are externally generated, so an id that happens to start with the prefix text must not collide with another session. #17127 - Added an optional
Phalcon\Config\ConfigFactoryconstructor parameter toPhalcon\Config\Adapter\Grouped. The factory is created once and reused for every configuration fragment, so custom adapters registered on a supplied factory are now visible when loading grouped configurations. #17134 - Added dialect-specific operators to PHQL:
@@,@>,<@,&&,||,->,->>,#>,#>>. Each is parsed into a binary expression and emitted only by the dialects that support it (PostgreSQL: all nine; MySQL:->,->>; SQLite:||,->,->>); using an operator on a dialect that does not support it throwsPhalcon\Db\Exceptions\UnsupportedOperator. The jsonb existence operators (?,?|,?&,@?) and the~regex family are intentionally unsupported - use their function equivalents (e.g.jsonb_exists(),regexp_like()). #14954 #14579 - Added geometry value objects under
Phalcon\Db\Geometry(Point,LineString,Polygon,MultiPoint,MultiLineString,MultiPolygon,GeometryCollection) and read-side hydration of spatial columns. Whenorm.cast_on_hydrateis enabled, spatial column values (MySQL WKB / PostGIS EWKB) are decoded into these objects on model read; otherwise the raw value is returned unchanged. #17110 #14769 #13670 - Added opt-in session locking to
Phalcon\Session\Adapter\Redis, preventing concurrent requests from racing on the same session (stale reads / lost writes). When enabled with the newlockingEnabledconstructor option,read()acquires a per-session lock (SET NX EX, retried with pauses) andclose()/destroy()release it with a token-guarded delete, so an adapter can only remove a lock it still owns. A read that cannot acquire the lock throwsPhalcon\Session\Adapter\Exceptions\AdapterRuntimeError. Tunable via thelockExpiry(lock TTL in seconds, default30),lockRetries(maximum attempts, default100) andlockWaitTime(microseconds between attempts, default50000) options. Locking is off by default. #17126 - Added table comment support to the MySQL and PostgreSQL dialects. Comment values are single-quote escaped (the existing PostgreSQL column-comment emission is now escaped as well). SQLite has no native table comment and ignores the option. #15258
- Added the
Phalcon\Contracts\Filter\Sanitizerinterface and moving array recursion inPhalcon\Filter\Filter::sanitize(). #17124
Fixed
- Fixed
Phalcon\Config\Config::cloneEmpty()so thatfilter(),map(),sort()andwhere()no longer fail on adapter instances (Ini,Json,Php,Yaml,Grouped). The override clones the current instance and replaces its data instead of invoking the adapter constructor with the parent(array $data, ...)signature. #17134 - Fixed
Phalcon\Config\Config::merge()emptying the configuration before validating its argument. Invalid merge data still throwsPhalcon\Config\Exceptions\InvalidMergeData, but the current configuration now survives intact. #17134 - Fixed
Phalcon\Config\Config::setData()bypassing thePhalcon\Support\Collectionruntime type guard: atypepassed to the constructor is now enforced on leaf values at every nesting depth (arrays become nested Config objects, which validate their own leaves). Nested Config objects also inherit thestrictNullandtypeflags in addition toinsensitive. #17134 - Fixed
Phalcon\Http\Cookie::send()fataling when the cookie has a non-empty definition and no DI container is set. The session integration (service lookup, started check, and the_PHCOOKIE_key convention) is now consolidated in privategetStartedSession()/getSessionKey()helpers shared bydelete(),restore()andsend(). #17127 - Fixed
Phalcon\Mvc\Model::groupResult()declaring aPhalcon\Mvc\Model\ResultsetInterfacereturn type while returning a scalar (int,float,string, ornull) for non-grouped aggregate queries (count(),sum(),average(),maximum(),minimum()). The return type declaration has been removed (@return int|float|string|null|ResultsetInterface), so model subclasses can overridegroupResult()without risking aTypeError. #17114 - Fixed
Phalcon\Mvc\Model::save()andPhalcon\Mvc\Model::update()to run the record-existence check on the write connection instead of the read connection. On master-replica setups, replication lag could make the check miss a row already written to the master, causingsave()to attempt anINSERTinstead of anUPDATE, orupdate()to fail withRecord cannot be updated because it does not exist.create()has used the write connection since #14256. #17105 - Fixed
Phalcon\Session\BagcallinggetDI()on itsPhalcon\Session\ManagerInterfaceconstructor parameter - a method the interface does not declare - which fataled for any manager implementing only the interface. The container i...
v5.14.1
5.14.1 (2026-06-08)
Tools
- Zephir Parser v2.0.4
- Zephir 0.23.0 (development - bae82f7bd)
Changed
- Consolidated the
Phalcon\Authdual-container handling (newPhalcon\Container\Containervs legacyPhalcon\Di\Di) behind a single internalPhalcon\Auth\Internal\ContainerResolver. #17088 [doc] - Renamed the private
Phalcon\Events\Managerdispatch hot-loop helper torunQueue(). #17006 [doc] - Reworked the
Phalcon\Authaccess gates into Specification-style policies.Phalcon\Contracts\Auth\Access\Access::isAllowed()now receives the current identity and the request context:isAllowed(Guard $guard, string $actionName, array $context = []), where context carrieshandler(controller / task / Micro component name),module(MVC module, when present), andparams(dispatcher or route parameters). #17088 [doc] Phalcon\Auth\Manager::access()now resolves gates throughPhalcon\Auth\Access\AccessLocatorfrom the container instead of constructing them directly. #17088 [doc]
Added
- Added
Phalcon\Auth\Access\Acl- an ACL-backed access gate that incorporates the role-based authorization of the old Firewall component (#14630) into the Auth layer. The gate checks the authenticated user's role against aPhalcon\Acl\Adapter\AdapterInterface: the ACL component is thehandlercontext key (prefixed withmoduleand a configurable separator when present), the ACL access is the action name, andparamsare passed through to callable ACL rules. Unauthenticated requests resolve to a configurable guest role (defaultguest); authenticated users supply their role viaPhalcon\Acl\RoleAwareInterface. #17088 [doc] - Added
Phalcon\Auth\Micro\AuthMicroListenerto enforce the active Auth access gate onPhalcon\Mvc\Microroute execution (attach to themicroevent space).#17088 [doc] - Added
Phalcon\Events\Manager::dispatch(object $event, string|array|null $name = null, ?object $source = null)for object/class-based event dispatch built on Phalcon's ownPhalcon\Contracts\Events\Stoppable. Listeners are routed by an explicit name (a string, or a[class, method]array) or by the event's class name and receive the event object. #17006 [doc] - Added
beforeBindandafterBindhook methods toPhalcon\Forms\Form. When defined on a form subclass,beforeBind(array $data, ?object $entity)runs at the start ofbind()(returningfalsecancels the bind) andafterBind(?object $entity)runs after the data has been assigned. Both also fire whenbind()is reached throughisValid(). #14598 [doc] - Added a
syncoption to many-to-many (hasManyToMany) relations and a chainablePhalcon\Mvc\Model::setSync()method to synchronize related records on save. When enabled, saving deletes the intermediate rows for records no longer present in the assigned array (add/update/delete), instead of only appending. #17071 [doc] - Added a
trace()method toPhalcon\Logger\Loggertogether with a newTRACElog level (value9, labeltrace). #17047 [doc] - Added a
{% verbatim %}/{% endverbatim %}tag to Volt. Its body is emitted exactly as written, without being parsed by Volt, so{{ ... }},{% ... %},{# ... #}and constructs such as<?xml ... ?>or client-side templates (Handlebars, Mustache, Angular) pass through untouched. #17085 [doc] - Added support for
JOINclauses in PHQLUPDATEstatements (e.g.UPDATE Invoices INNER JOIN Customers ON ... SET ... WHERE Customers.cst_id = :id:). The join is used to filter the records to update; the statement still targets a single model. #16984 [doc]
Fixed
- Fixed PHQL parser cache to use string-keyed lookups (
zend_hash_str_find/zend_hash_str_update) instead of integer keys derived fromzend_inline_hash_func, eliminating hash collisions that caused different PHQL queries to return identical cached ASTs #14791 - Fixed
Phalcon\Annotations\Readerfailing to parse a docblock when an annotation argument is a string literal containing a parenthesis (e.g.@SomeAnnotation(key='value(')). The docblock pre-scan that locates each@Annotation(...)span counted every(/), including those inside quoted values, so an unbalanced parenthesis in a string consumed the rest of the comment and produced a "Scanning error". #16084 - Fixed
Phalcon\Di\Injectable::__get()to no longer cache resolved services as dynamic object properties. Services accessed via magic properties (e.g.$this->request) are now re-resolved through the container on each access, so replacing or updating a service in the container is reflected in controllers, views, and other injectable classes. Properties already declared on the class continue to be populated. #17052 - Fixed
Phalcon\Encryption\Crypt::decrypt()to verify the HMAC tag with the constant-timehash_equals()instead of the identity operator, removing an observable timing discrepancy in the tag comparison (CWE-208, CWE-347) . The tag is now also verified before the decrypted text is unpadded, and truncated tags are rejected by the unequal-length path ofhash_equals(). #17090 [doc] - Fixed
Phalcon\Mvc\Model\Query\Builder::orderBy()when the array syntax is used with complex PHQL expressions. Previously any array item containing a space was split as a simplecolumn directionpair, corrupting expressions such asCASE WHEN inv_status_flag = 1 THEN 0 ELSE 1 END ASC. The builder now only treats a trailingASC/DESCas the direction (autoescaping a simple column) and preserves complex expressions verbatim. #17077 - Fixed
Phalcon\Mvc\Model\Query(PHQL) parsing of identifiers whose name begins with theNOTkeyword. Columns, tables, and aliases such asnotice_idwere truncated toice_id(the leadingnotwas dropped), causing the database to report the column as unknown - most visibly inPhalcon\Mvc\Model\Query\Builderjoin conditions built viacreateBuilder(). The scanner's re2c backtracking marker shared the token-start pointer, so theNOT BETWEENrule advanced it pastnot; escaped identifiers containing internal escapes (e.g.[col\[0\]]) were corrupted by the same root cause. #16831 #17087 - Fixed the compilation failure (
'name_zv' undeclared) inPhalcon\Container\Container::callableGet()andcallableNew(). Both closures captured the typedstring nameparameter directly viause (name). #17078
Removed
- Removed the unfinished
{% raw %}/{% endraw %}Volt tag. It never produced output (compilation threwUnknownVoltStatement) and its body was parsed rather than emitted literally. Use{% verbatim %}instead. #17085
v5.14.0
5.14.0 (2026-06-04)
Tools
- Zephir Parser v2.0.2
- Zephir 0.22.0 (development - 9d2def774)
Changed
- Alignment with v6; docblocks; sorting; return types; minor fixes (image watermark opacity calc, serializer/helpers, readonly-becoming-mutable, ACL local access). #17055
- Changed return types to
-> <static>or-> <self>in various components. The change is a covariant narrowing on implementation methods and does not touch any interface contracts, so userland classes that implement Phalcon interfaces and return the interface type continue to work unchanged. #17035 - Internal performance work across
Autoload,Dispatcher,Annotations,Db,Mvc\Model,Mvc\Model\Query,Tag,Assets,Acl\Adapter\Memory,Http\Request,Encryption\Crypt. Behavior preserved. #17049 - Moved CI tools/scripts in
resources/removed unused ones #17066 - Moved docker in
resources/#17066 - Refactored docker images (more flexible less cruft) #17066
- Reorganization of quality tool config files (in
resources/) #17066 Phalcon\Autoload\Loadergetters (getDirectories,getExtensions,getFiles) return arrays keyed by the value string instead of by a SHA256 hash of it; iteration order and contents are unchanged. #17049 [doc]Phalcon\Mvc\Router::handle()internal optimizations: O(1) hash lookup for literal-URI routes; per-HTTP-method buckets; hot-loop reads; PCRE patterns chunked; per-route metadata cache deduplicated by route id. #17012 [doc]Phalcon\Mvc\Router\Route::getCompiledHostName()now uses cache for hostname/converters. #17012 [doc]
Added
- Added a new dependency-injection container under
Phalcon\Container, with its contracts underPhalcon\Contracts\Container. It adds:Phalcon\Container\Container/Phalcon\Container\ContainerFactory- the container and its factory, configured throughPhalcon\Contracts\Container\Service\Providerproviders (Phalcon\Container\Provider\Web,Phalcon\Container\Provider\Cli).Phalcon\Container\Definition\ServiceDefinition- fluent service definitions with autowiring, factories, extenders, tags, aliases, and configurable service lifetimes (Phalcon\Container\Definition\ServiceLifetime).Phalcon\Container\Resolver\Resolver- reflection-based constructor / method / parameter autowiring, plus thePhalcon\Container\Resolver\Lazy\*family for lazy resolution (Get,GetCall,NewInstance,Call,Env,CsEnv,ArrayValues, etc.).Phalcon\Container\Exceptions\*- granular, per-cause exceptions (ServiceNotFound,CircularAliasFound,FrozenDefinition,CannotResolveParameter,NoProcessorFound, etc.). #16897 [doc]
- Added a new authentication and authorization layer under
Phalcon\Auth, with its contracts underPhalcon\Contracts\Auth. Built on top ofPhalcon\Container, it adds:Phalcon\Auth\Manager/Phalcon\Auth\ManagerFactory- the central manager that wires guards and access gates together, and its factory.Phalcon\Auth\AuthUser- a lightweight user value object returned by array-backed adapters when no application model class is configured.- Guards under
Phalcon\Auth\Guard-SessionandToken(withAbstractGuardandUserRemember), resolved viaPhalcon\Auth\Guard\GuardLocatorand configured throughPhalcon\Auth\Guard\Config\*(AbstractGuardConfig,SessionGuardConfig,TokenGuardConfig). - Adapters under
Phalcon\Auth\Adapter-Memory,Model, andStreamuser providers (withAbstractAdapterandAbstractArrayAdapter), resolved viaPhalcon\Auth\Adapter\AdapterLocatorand configured throughPhalcon\Auth\Adapter\Config\*(AbstractAdapterConfig,MemoryAdapterConfig,ModelAdapterConfig,StreamAdapterConfig). - Access gates under
Phalcon\Auth\Access-AuthandGuest(withAbstractAccess), resolved viaPhalcon\Auth\Access\AccessLocator. - Dispatcher listeners
Phalcon\Auth\Mvc\AuthDispatcherListenerandPhalcon\Auth\Cli\AuthDispatcherListener(withPhalcon\Auth\AbstractAuthDispatcherListener) to guard MVC and CLI dispatch. Phalcon\Auth\Exceptionplus granularPhalcon\Auth\Exceptions\*(AccessDenied,ConfigRequiresNonEmptyValue,DataMustContainIdKey,DoesNotImplement,FileCannotRead,FileDoesNotContainJson,FileDoesNotExist,FileNotValidJson).- Contracts under
Phalcon\Contracts\Auth-Manager,AuthUser,AuthRemember,RememberToken,Access\Access,Adapter\Adapter,Adapter\AdapterConfig,Adapter\RememberAdapter,Guard\Guard,Guard\GuardConfig,Guard\GuardStateful,Guard\BasicAuth. Phalcon\Support\AbstractLocator- the shared service-locator base extended by the guard, adapter, and access locators. #16273 [doc]
- Added granular exception classes across the framework. Every namespace that previously surfaced failures through a single umbrella
Phalcon\<Namespace>\Exception(or its sub-namespace counterpart) now ships per-cause classes under a siblingExceptions/folder. Each new class extends the existing per-namespace parent socatch (Phalcon\<Namespace>\Exception $e)continues to work unchanged. New classes:Phalcon\Acl\ExceptionsAccessRuleNotFoundCircularInheritanceErrorElementNotFoundForbiddenWildcardInvalidAccessListInvalidComponentImplementationInvalidRoleImplementationInvalidRoleTypeMissingFunctionParametersParameterTypeMismatchRoleNotFoundException
Phalcon\Annotations\ExceptionsAnnotationNotFoundAnnotationsDirectoryNotWritableCannotReadAnnotationDataUnknownAnnotationExpression
Phalcon\Application\ExceptionsModuleNotRegistered
Phalcon\Assets\ExceptionsAssetSourceTargetCollisionCannotReadAssetCollectionNotFoundInvalidAssetSourcePathInvalidAssetTargetPathInvalidFilterInvalidTargetPathTargetPathIsDirectory
Phalcon\Autoload\ExceptionsLoaderDirectoriesNotArrayLoaderMethodNotCallable
Phalcon\Cache\ExceptionCacheKeysNotIterableInvalidCacheKey
Phalcon\Cli\Console\ExceptionsConsoleModuleNotRegisteredContainerRequiredInvalidModuleDefinitionPathModuleDefinitionPathNotFound
Phalcon\Cli\Router\ExceptionsBeforeMatchNotCallableInvalidRoutePathsRouterArgumentsInvalidType
Phalcon\Config\ExceptionsCannotLoadConfigFileConfigNotArrayOrObjectGroupedAdapterRequiresArrayInvalidMergeDataMissingConfigOptionMissingFileExtensionMissingYamlExtension
Phalcon\DataMapper\Pdo\ExceptionDriverNotSupportedUnknownDriverMethodUnknownQueryMethod
Phalcon\Db\ExceptionsCannotInsertWithoutDataCannotPrepareStatementCheckExpressionRequiredColumnTypeRejectsAutoIncrementColumnTypeRejectsScaleColumnTypeRequiredConflictTargetColumnRequiredConflictUpdateColumnRequiredForeignKeyColumnsRequiredGeneratedAutoIncrementConflictGeneratedDefaultConflictIncompleteBindTypesInvalidBindParameterInvalidCheckExpressionInvalidGenerationExpressionInvalidGroupByExpressionInvalidIndexColumnsInvalidIndexDirectionsInvalidIndexWhereInvalidListExpressionInvalidOrderByExpressionInvalidSqlExpressionInvalidSqlExpressionTypeInvalidUnaryExpressionInvalidWhereConditionsMatchedParameterNotFoundMaterializedViewsNotSupportedMissingDefinitionKeyMissingForeignKeyChecksMissingSqliteDatabaseMysqlOnConflictNotSupportedNestedTransactionChangeBlockedNoActiveTransactionReferencedColumnCountMismatchReferencedColumnsRequiredReferencedTableRequiredReturningNotSupportedReturningRequiresColumnSavepointsNotSupportedSqliteAlterCheckNotSupportedSqliteAlterColumnNotSupportedSqliteAlterForeignKeyNotSupportedSqliteAlterPrimaryKeyNotSupportedSqliteDropCheckNotSupportedSqliteDropForeignKeyNotSupportedSqliteDropPrimaryKeyNotSupportedTableMustHaveColumnUnrecognizedDataTypeUpdateFieldCountMismatch
Phalcon\Di\ExceptionsAliasAlreadyInUseAliasNameMustBeStringArgumentTypeRequiredCallArgumentsMustBeArray- `CircularAliasRefere...
v5.13.0
5.13.0 (2026-05-18)
Changed
- Changed
Phalcon\Contracts\Support\Collectionto declare the expanded method surface (column,each,filter,first,getType,isEmpty,keys,last,map,reduce,replace,sort,values,where) so the contract matches the implementation #17000 [doc] - Changed
Phalcon\Events\Eventto be declaredfinal. The class is a value object holdingtype,source,data,cancelable, andstopped; no subclasses exist in the cphalcon tree and any future typed-event work would add new sibling classes implementingEventInterfacerather than extendingEvent. Marking itfinallets the C extension fold the per-fire getters (getType,getSource,getData,isCancelable,isStopped,isPropagationStopped) into direct dispatch. BC note: any userlandclass MyEvent extends Eventnow fails #17006 [doc] - Changed
Phalcon\Events\Manager::attach()to classify the handler kind once at attach time so the dispatch loop can route via a single branch instead of runninginstanceof Closure/is_callable/typeofper fire per listener. Four kinds are recognized:0= Closure (direct invocation via Zephir's{handler}(args)syntax, no arg-array allocation),1=[obj, method]array callable (direct dynamic dispatchhandler[0]->{handler[1]}(args), nocall_user_func_arrayoverhead),2= plain object with method named after the event - the classic Phalcon listener pattern (class name is captured at attach time and stored on the tuple to skipget_class()per fire),3= generic callable (string function name, invokable object,[class, staticMethod]) routed throughcall_user_func_array. The subscriber array-form attach paths ([methodName, priority]and[[methodA, priorityA], [methodB, priorityB]]) now route throughinsertHandlerEntrydirectly withkind=1, bypassing the classification cascade since the resulting handler shape is already known.methodExistsCacheaccess in the dispatch loop is tightened to a singleissetfast path #17006 [doc] - Changed
Phalcon\Events\Manager::detach()to drop theeventTypekey entirely when its queue empties (removing the last listener), sohasListeners()andfire()'s short-circuit tell the truth. Previously an emptied queue left the key in place with an empty array value, causingisset($this->events[$eventType])to returntruewith no actual listeners to dispatch to. The matchingDetachTestexpectations are updated to reflect the new contract #17006 [doc] - Changed
Phalcon\Events\Manager::detachAll(null)to reseteventsto[]instead ofnull. The previousnullreset brokeisset($this->events[$key])semantics insideattach()andfire()until the next assignment refilled the property; the empty-array form keeps all access paths consistent #17006 [doc] - Changed
Phalcon\Events\Manager::fire()andPhalcon\Events\Manager::fireAll()to wrap dispatch intry { ... } catch \Throwable, ex { cleanup; throw ex; }. A throwing listener restores stashed responses (if nested) and decrementsfireDepthback to its pre-call value before the exception propagates, so manager state stays clean for the next fire - important for long-lived managers (workers, daemons) where a single dirty teardown would poison every subsequent fire #17006 [doc] - Changed
Phalcon\Events\Manager::fire()to parse theeventTypeonly once per unique string and cache the result ([typePrefix, eventName]) in an internaleventNameCachekeyed by the original string. Repeated fires of the same event name (db:beforeQuery × Nper request, model lifecycle events on hot save paths) collapse to a single hash lookup after warm-up. The cache never needs invalidation because the parse is deterministic for a given input string.fire()also short-circuits before allocating theEventinstance when no listeners match either the type queue or the fully-qualified queue - in production most fires have zero matching listeners (model lifecycle events with no user-attached behavior, DB events without a tracer), so the avoided allocation is significant in hot paths #17006 [doc] - Changed
Phalcon\Events\Manager::fire(),Phalcon\Events\Manager::attach(), andPhalcon\Events\Manager::fireQueue()to be declaredfinal. The class itself stays open so genuine subclasses that only add new methods continue to work, but the dispatch hot path is locked to enable C-level direct dispatch on the three methods that run per-event. The remaining public surface (addSubscriber,removeSubscriber,detach,detachAll,getListeners,getResponses,getSubscribers,hasListeners,isCollecting,isValidHandler,collectResponses,enablePriorities,arePrioritiesEnabled,isStrict,setStrict,fireAll,clearSubscribers) is left non-finalso decorator-style subclasses that wrap these less-hot methods can still override them. BC note: subclasses that overridefire,attach, orfireQueuenow fail #17006 [doc] - Changed
Phalcon\Events\Manager::fireQueue()to be a thin BC-preserving wrapper around a new privatePhalcon\Events\Manager::dispatch()helper. The public signaturefireQueue(array $queue, EventInterface $event)is unchanged; the framework's ownfire()path bypassesfireQueueand callsdispatch()directly with hoisted arguments (eventName,source,data,cancelable,collect) so the second dispatch leg of a two-queuefire()(type queue + fully-qualified queue) does not re-extract identical values from the event. The dispatch path also applies a single-handler fast path: when the queue has exactly one listener (very common in unit tests and lightly-instrumented production), the foreach plus per-iteration cancelable/isStopped check is skipped and dispatch goes straight through the type-branch #17006 [doc] - Changed
Phalcon\Events\Managerdispatch return-value contract to last non-null wins. Previously every listener return overwrote the runningstatus, so a chain of ("value",null) ended withfire()returningnulland silently losing the earlier real value. The new contract only updatesstatuswhen the listener return is non-null - the last meaningful return survives. Thestop()determinism rule overrides last-non-null: when a listener calls$event->stop()(andcancelable=true), that listener's return value is whatfire()returns - even ifnull- because the caller asked for the stopping listener's verdict explicitly. Returningfalsefrom a listener does not short-circuit the queue; callers wanting to stop downstream listeners must call$event->stop(). Consumers likePhalcon\Mvc\Dispatcherthat interpret afalsereturn fromfire()as a cancel signal are unaffected because that check happens in their own dispatch logic, not in the events manager #17006 [doc] - Changed
Phalcon\Events\Managerlistener storage fromSplPriorityQueueto a sorted array of[handler, type, priority]tuples (with an additionalclassNameelement ontype=2tuples). TheSplPriorityQueue::EXTR_BOTHclone-per-fire and O(n)setExtractFlags()rebuild on detach are eliminated; the "empty heap" warnings produced bySplPriorityQueueon never-fired event types disappear as a side effect. Insert order under the same priority is preserved (FIFO). WhenenablePrioritiesis off (the default),insertHandlerEntryshort-circuits to a plain append - the sorted-insert loop only runs when priorities are explicitly enabled. When it does run, the insert usesarray_spliceinstead of a per-element rebuild #17006 [doc] - Changed
Phalcon\Html\Escaperinto a façade over five per-context escapers (Phalcon\Html\Escaper\HtmlEscaper,AttributeEscaper,CssEscaper,JsEscaper,UrlEscaper); each is reachable viagetXxxEscaper()/setXxxEscaper()so individual contexts can be swapped without subclassing the façade. The legacysetEncoding(),setFlags(), andsetDoubleEncode()setters fan out to all sub-escapers so existing code keeps working #16971 [doc] - Changed
Phalcon\Html\Helper\AbstractSeries::__toString()toksort()itsstorebefore rendering so entries are emitted in position order rather than registration order. #16971 [doc] - Changed
Phalcon\Html\Helper\Input\CheckboxandPhalcon\Html\Helper\Input\Radioto extend a new sharedPhalcon\Html\Helper\Input\AbstractChecked;Radiono longer extendsCheckbox. Two paths now renderchecked="checked": the unconditional opt-ins["checked" => "checked"](case-insensitive) and["checked" => true], and a value-match path comparing the suppliedcheckedattribute against the input'svalue(==by default for mixed i...
v5.12.1
5.12.1 (2026-04-30)
Added
- Added
Phalcon\Db\Column::TYPE_UUIDconstant (value29) and added support for PostgreSQL nativeuuidcolumn type inPhalcon\Db\Adapter\Pdo\PostgresqlandPhalcon\Db\Dialect\Postgresql#16840 - Added support for
Phalcon\Mvc\Urlstatic base URI inPhalcon\Assets\Manager; when a DI container is set and aurlservice is available, local asset paths are now resolved viagetStatic()instead of a bare/prefix #16570
Fixed
- Fixed
Phalcon\Mvc\Model\MetaDataInterface::readMetaDataIndex()andPhalcon\Mvc\Model\MetaData::readMetaDataIndex()declaring return type asarray|nullwhen the method can also return astring(e.g. forMODELS_IDENTITY_COLUMN), causing a PHP fatal error on PHP 8+ #16613 - Fixed
Phalcon\Mvc\View\Engine\Volt\Compiler::statementList()returningnullinstead ofstringwhen processing templates that consist entirely of block-mode statements, causing a PHP fatal error on PHP 8+ #16613 - Fixed
Phalcon\Forms\Element\Select::render()multiselect regression introduced in v5.12.0 (#16894) by reverting toPhalcon\Tag\Select::selectField(); the newHtml\Helper\Input\Selectonly supports a single selected value and does not handle array values required for multiselect #16946 - Fixed
Phalcon\Html\Helper\Input\AbstractInput::setValue()ignoring empty string""as a valid value, causingCheckboxandRadioinputs withvalue=""to never renderchecked="checked"even when thecheckedattribute matched #16648 - Fixed
Phalcon\Http\Response\Cookies::get()throwing an opaque fatal error when no DI container has been set; it now throwsPhalcon\Http\Cookie\Exceptionwith a descriptive message before accessing the container #16650 - Fixed
Phalcon\Mvc\Model\MetaData::writeMetaDataIndex()prematurely initializing a child model's metadata with the parent's source table whenskipAttributes()(orskipAttributesOnCreate()/skipAttributesOnUpdate()) is called inside a parent model'sinitialize()and the child callsparent::initialize()before setting its own source, corrupting the child's attribute list and breaking relationship resolution #16544 - Fixed
Phalcon\Storage\Serializer\Json::serialize()rejecting plain objects (e.g.stdClass) that do not implementJsonSerializable;json_encode()handles such objects natively and the guard was unnecessary #16630 - Fixed
Phalcon\Mvc\Model\Managerretaining a model instance inlastInitializedafter initialization andPhalcon\Mvc\Modelnot clearing the reusable-records cache aftersave(), causing memory to grow unboundedly in long-running processes #16566 - Fixed
Phalcon\Paginator\Adapter\QueryBuilder::paginate()returning wrong total item count when the query usesDISTINCTcolumns; the count now usesCOUNT(DISTINCT ...)for a single column and a subquery for multiple columns #16581 - Fixed
Phalcon\Mvc\Model\Query\Builder::autoescape()incorrectly wrapping function expressions (e.g.DATE_PART(...)) in brackets when used ingroupBy(), causing a"Column does not belong to any of the selected models"exception #16599 - Fixed
Phalcon\Mvc\Model- saving a model with multiple fields relations threw"Not implemented"#16029
v5.12.0
5.12.0 (2026-04-29)
Changed
- Changed
Phalcon\Assets\Managerfilter type check fromis_object()totypeofand updated the error message to"The filter is not valid"#16889 - Changed
Phalcon\Cache\AbstractCache::doDeleteMultiple()to delegate to the storage adapter'sdeleteMultiple()instead of looping over individualdelete()calls #16859 - Changed
Phalcon\Di\Exceptionmessage for missing services from"was not found in the dependency injection container"to"is not registered in the container"#16889 - Changed
Phalcon\Di\Service\Buildererror messages for service parameters to use double quotes instead of single quotes #16889 - Changed
Phalcon\Forms\Element\AbstractElement::getLocalTagFactory()to throwPhalcon\Forms\Exceptioninstead of silently creating a newTagFactorywhen neithersetTagFactory()nor a parentFormprovides one #16894 - Changed
Phalcon\Forms\Element\Select::render()to useTagFactory-basedHtml\Helper\Input\Selectinstead of the deprecatedPhalcon\Tag\Select#16894 - Changed
Phalcon\Html\TagFactoryto accept an optionalResponseInterfacein the constructor (useful forpreload) #16892 - Changed
Phalcon\Mvc\ControllerandPhalcon\Mvc\View\Engine\AbstractEngineto be events aware #16890 - Changed
Phalcon\Mvc\View\Engine\Volt\Compiler::setOptionsto return$thisnow #16891 - Changed calls to
globals_getandglobals_setin the code withPhalcon\Support\Settings::get()/set()#16884 - Changed exception messages across multiple components to use
"does not"instead of"doesn't"for consistency #16889
Added
- Added
Phalcon\Encryption\Security\Uuidfactory and versioned adapters (Version1–Version7) with aUuidInterfacecarrying standard RFC 4122 namespace constants; each version is a singleton cached by the factory, invoked viav1()–v7()#16326 - Added
Phalcon\Html\Helper\FriendlyTitle- available viaTagFactoryasfriendlyTitle[#16892(https://github.com//issues/16892) - Added
Phalcon\Html\Helper\Input\Select::fromData()to populate select options from aSelectDataInterfaceprovider, with optgroup support #16894 - Added
Phalcon\Html\Helper\Input\Select\SelectDataInterface,Phalcon\Html\Helper\Input\Select\ArrayData, andPhalcon\Html\Helper\Input\Select\ResultsetDataas data providers for theSelecthelper #16894 - Added
Phalcon\Html\Helper\Preload- available viaTagFactoryaspreload;TagFactorynow accepts an optionalResponseInterfaceas its third constructor parameter [#16892(https://github.com//issues/16892) - Added
Phalcon\Mvc\Model\Resultset::refresh()to re-execute the underlying query and update the resultset with fresh data from the database #16409 - Added
deleteMultiple()toPhalcon\Storage\Adapter\*to delete multiple keys in a single operation using native batch capabilities per adapter #16859 - Added key validation per entry in
Phalcon\Cache\AbstractCache::doDeleteMultiple()throwingInvalidArgumentExceptionfor keys containing invalid characters #16859 - Added named static factory methods
Phalcon\Forms\Exception::tagFactoryNotFound()andPhalcon\Forms\Exception::usingParameterRequired()#16894
Fixed
- Fixed
Phalcon\Db\Dialect\Postgresql::modifyColumn()to generate correct SQL when changing a boolean column's default value: replacedemptycheck withhasDefault()to avoid treatingfalseas "no default", removed the boolean-only branch that omitted theALTER TABLEprefix, and fixedcastDefault()to return PostgreSQL literalstrue/falseinstead of raw PHP booleans #15829 - Fixed
Phalcon\Db\Result\PdoResult::$rowCountto usenullas the uninitialised sentinel instead offalse, preventing a count of0rows being confused with "not yet counted" #16409 - Fixed
Phalcon\Dispatcher\AbstractDispatcher::dispatch()to refresh the localeventsManagerandhasEventsManagervariables afterinitialize()returns, so that an events manager attached to the dispatcher insideinitialize()is honoured for all subsequent dispatch events (afterInitialize,afterExecuteRoute,afterDispatch,afterDispatchLoop, etc.) #16440 - Fixed
Phalcon\Filter\Validation::bind()to skip the dependency injection container lookup whendatais empty, preventing unnecessaryDi\Exceptionerrors #16889 - Fixed
Phalcon\Filter\Validation\AbstractValidator::allowEmpty()to support a value-list array (e.g.[null, '']) in addition to the per-field map syntax, using strict===comparison so that'0'is never silently treated as empty #15491 - Fixed
Phalcon\Filter\Validation\AbstractValidator::messageFactory()to pass the joined field string toPhalcon\Messages\Messageinstead of the raw array when multiple fields are provided #16889 - Fixed
Phalcon\Filter\Validation\Validator\Alpha::validate()to returnfalsewhenallowEmptyis explicitly set tofalseand the submitted value isnullor an empty string #16200 - Fixed
Phalcon\Forms\Form::isValid()to apply field filters even when no validators are specified (again) #16830 - Fixed
Phalcon\Html\Escaper::css()andPhalcon\Html\Escaper::js()to return an empty string instead offalsewhen the input is empty or contains only a null codepoint #16889 - Fixed
Phalcon\Html\Helper\AbstractHelper::renderAttributes()to emit boolean HTML5 attributes (e.g.async,defer) as standalone attribute names instead ofasync="1"when the attribute value istrue#16304 - Fixed
Phalcon\Html\Helper\Breadcrumbsto support subdirectory installs: addedgetPrefix()/setPrefix()for a manual string prefix, and an optionalUrlInterfaceconstructor parameter that resolves links throughurl->get()(including base URI prepending and double-slash normalisation);TagFactoryaccepts an optional fourthUrlInterfaceargument and passes it toBreadcrumbsautomatically #14957 - Fixed
Phalcon\Http\Response::setStatusCode()exception message from"Non-standard statuscode given without a message"to"Non-standard status-code given without a message"#16889 - Fixed
Phalcon\Image\Adapter\AbstractAdapter::crop()to correctly handleoffsetX = 0andoffsetY = 0by changing the parameter types frominttovar; the previousinttyping caused Zephir to compile thenullcheck as0 == offsetin C, making explicit zero offsets indistinguishable from omitted (center) offsets #16156 - Fixed
Phalcon\Image\Adapter\Gd::processResize()to preserve PNG alpha channel transparency by replacingimagescale()withimagecreatetruecolor()+imagealphablending(false)+imagesavealpha(true)+imagecopyresampled()#16316 - Fixed
Phalcon\Image\Adapter\Imagick::processPixelate()to explicitly cast division result tointto prevent implicit float-to-int deprecation #16889 - Fixed
Phalcon\Mvc\Model::__get()to return the already-loaded related record instead of re-fetching from the database, preventing modifications to relation properties from being discarded #15554 - Fixed
Phalcon\Mvc\Model::__unserialize()andPhalcon\Mvc\Model::unserialize()to callonConstruct()after deserialization, so typed properties initialized inonConstructare correctly set when a model is restored from cache #15906 - Fixed
Phalcon\Mvc\Model::__unserialize()andPhalcon\Mvc\Model::unserialize()to restore snapshot as the current attributes (instead of null) when a model is deserialized with no pending changes, preventinggetChangedFields()from throwing after cache retrieval #15837 - Fixed
Phalcon\Mvc\Model::cloneResultMap()to call model setter methods (e.g.setName()) during ORM hydration whenorm.disable_assign_settersisfalse, making hydration behaviour consistent withassign(); setters inlocalMethods(Phalcon internals) are excluded #14810 - Fixed
Phalcon\Mvc\Model::collectRelatedToSave()to skip unmodifiedhasOne/hasManyrelated records that have snapshot data, preventing spuriousINSERT/UPDATEstatem...
v5.11.1
5.11.1 (2026-04-04)
Changed
Added
- Added
Phalcon\Storage\Adapter\RedisClusteradapter to support Redis Cluster connections #16867 - Added
Phalcon\Support\Settingsto be used for ini settings throughout the framework #16873
Fixed
- Fixed
Phalcon\Encryption\Security::computeHmac()to catch\ValueErrorthrown by PHP 8.1+ when an unknown hashing algorithm is passed #16893
Removed
v5.11.0
5.12.0 (2026-04-03)
Changed
- Changed
Phalcon\Filter\Sanitize\IPto optimize the sanatization of IP address #16838 - Changed
Phalcon\Encryption\Security\JWT\Builder::setPassphrase()to require digits and special characters #16847 - Changed
Phalcon\Encryption\Security\JWT\Builder::getAudience()to return an empty array if not set #16846 - Changed
Phalcon\Encryption\Security\Random::base()to use 16 bits by default #16845 - Changed
Phalcon\Logger\Loggerto use lowercase when reporting log levels (previously uppercase) #16852 - Changed
Phalcon\Logger\Adapter\Streamto use a more efficient way to write messages in the logger instead of opening and closing the stream per message #16852 - Changed
Phalcon\Logger\Adapter\Syslogto use theEnuminstead ofLoggerconstants #16852 - Changed the whole testing suite to run on phpunit only #16860 #16861 #16862
Added
- Added PIE (PHP Installer for Extensions) support #16832
- Added the ability to specify aliases for
Phalcon\Di\Diservices.#13042 - Added
Phalcon\Encryption\Security\JWT\Validator::validateClaim()to validate custom claims #16843
Fixed
- Fixed
Phalcon\Forms\Form::isValid()to apply field filters even when no validators are specified #16936 - Fixed
Phalcon\Http\RequestmethodgetClientAddress()when usingtrustForwardedHeader#16836 - Fixed
Phalcon\Acl\Adapter\Memory::isAllowed()andPhalcon\Mvc\Model\Binderto handle PHP 8.1+ union and intersection types by checking forReflectionNamedTypebefore callinggetName()#16261 - Fixed memory leak in PHQL parser (phql_internal_parse_phql()) during repeated query execution. #16854
- Fixed a deadlock issue when running the db suite #16862
Removed
v5.10.0
5.10.0 (2025-12-25)
Changed
- Changed
bind()andvalidate()method inPhalcon\Filter\ValidationandPhalcon\Filter\Validation\ValidationInterfaceto accept$whitelistarray of only allowed fields to be mutated when using entity #16800 - Changed
Phalcon\Storage\Adapters\Libmemcached::getAdapter()to use 50ms for\Memcached::OPT_CONNECT_TIMEOUT#16818 - Changed
Phalcon\Html\Helper\Input\*to honorDocblocdirectives #16778
Added
- Added
fails()method helper toPhalcon\Filter\Validationuseful for standalone validation #16798
Fixed
- Fixed
Phalcon\Config\Adapter\Yamlconstructor to handlenullreturn values fromyaml_parse_file(), ensuring empty configuration files are treated as empty arrays instead of throwing errors. - Fixed
Phalcon\Http\RequestmethodgetClientAddress(true)to return correct IP address from trusted forwarded proxy. #16777 - Fixed
Phalcon\Http\RequestmethodgetPost()to correctly return json data as well and unified bothgetPut()andgetPatch()to go through the same parsing method. #16792 - Fixed
Phalcon\Filter\Validationmethodbind()andvalidate()to correctly bind data when using entity as well as skip binding of fields not included in$whitelist#16800 - Fixed
Phalcon\Http\RequestmethodgetPostData()whenContent-Typeheader is not set #16804 - Fixed
Phalcon\Events\ManagerInterfaceadding priority property #16817 - Fixed
Phalcon\Storage\Adapters\Libmemcached::getAdapter()to correctly merge adapter options #16818 - Fixed
Phalcon\Encryption\CryptmethodcheckCipherHashIsAvailable(string $cipher, string $type)to correctly check thecipherorhashtype #16822 - Fixed
Phalcon\Mvc\Modeldocblocks #16825
v5.9.3
5.9.3 (2025-04-19)
Changed
- Added Multi-Stage Dockerfile and Github action for release Docker images to ghcr.io and Docker Hub. #16752
Added
- Added
Phalcon\Mvc\Router::setUriSource()to allow URI processing from$_GET['url']or$_SERVER['REQUEST_URI']as it was in v3 #16741
Fixed
- Fixed
Phalcon\Mvc\Routerto correctly handle numeric URI parts as it was in v3 #16741 - Fixed
Phalcon\Mvc\Model\Binderto use ReflectionParameter::getType() instead of deprecated method, PHP 8.0 or higher issue. #16742 - Fixed
Phalcon\Mvc\Model\Queryto check if cache entry exists. #16747 - Fixed
Phalcon\Mvc\Routerto correctly match route when using query string URIs. #16749 - Fixed
Phalcon\Mvc\Model::cloneResultsetto properly parse fields that do not acceptnullvalues #16736