It is specifically implemented for being used inside Eel, the Embedded Expression
Language for Flow.
Essentially, a FlowQuery object is a container for an *ordered set* of objects
of a certain type. On this container, *operations* can be applied (like
filter(), children(), ...).
All of these operations work on a *set*, that is, an operation usually expands
or shrinks the set of objects.
An operation normally returns a new FlowQuery instance with the operation applied,
but there are also some operations like is(...) or count(), which return simple
types like boolean or numbers. We call these operations *final operations*.
Internal Workings
=================
To allow for optimization, calling operations are not immediately executed.
Instead, they are appended to a *list of operations*. Only if one tries to
iterate over the FlowQuery object or calls a final operation, the operations
get executed and the result is computed.
Implementation of Operations
----------------------------
Operations are implemented by implementing the {@link OperationInterface} or,
more commonly, subclassing the {@link Operations/AbstractOperation}.
An operation must be *equivalence preserving*, that is, the following equation
must always hold:
applyAllOperations(context) = applyRemainingOperations(applyOperation(context))
While an operation is running, it can *add new operations* to the front of the
operation queue (with {@link pushOperation()}), so for example count($filter)
can first apply filter($filter), followed by count(). However, when doing this,
great care must be applied by the operation developer in order to still have
finite runs, and to make sure the operation is *equivalence preserving*.
Furthermore, an operation can *pop* its following operations from the operation
stack, and *peek* what the next operation is. It is up to the operation developer
to ensure equivalence preservation.
An operation may *never* invoke __call() on the FlowQuery object it receives;
as this might lead to an undefined state; i.e. you are not allowed to do:
$flowQuery->someOtherOperation() *inside* an operation.
Final Operations
----------------
If an operation is final, it should return the resulting value directly.