Fun: Functional Programming in PHP¶
Tutorials¶
How-to Guides¶
Fun API Reference¶
Operators¶
Operators are what you would expect in the mathematical sense e.g addition, subtraction, equality.
Fun provides a large number of operators as PHP functions and callable constants. These are designed to:
Accept primitive PHP types
Be used as first-class functions
When to use Fun operators¶
In simple cases, e.g when comparing two values known to be primitive, you should use PHP’s built in operators. But, for comparing your own types or Fun types, use these operators.
Using operators¶
To use them as functions, import as functions:
use function Fun\eq;
And to use them as first-class values, import as constants:
use const Fun\eq;
Note
This is because PHP has separate symbol tables for functions and constants. This may change in a near-future version of PHP.
Equivalence¶
eq¶
eq :: Eq a -> Eq a -> Boolean
For PHP primitives, the eq
operator is equivalent to ===
such that the following holds:
eq(1, 1) && 1 === 1
Unlike ===
, eq
compares equivalence of objects that implement the type Fun\Types\Eq
.
eq
expects implementations to hold the properties of equivalence relations, namely:
Reflexivity i.e
eq($x, $x) === true
Symmetry i.e
eq($x, $y) === eq($y, $x)
Transitivity i.e
!(eq($x, $y) && eq($y, $z)) || eq($x, $z)
Implementations that do not have these properties are errorneous.
neq¶
neq :: Eq a -> Eq a -> Boolean
neq
is defined as the complement of neq
. It is implemented in kind. Any type that implements Fun\Types\eq
gains a working neq
operator.
It is equivalent to PHP’s !==
operator.
Ordering¶
lt
lte
gt
gte
min
max
compare
Booleans¶
_and
_or
_not
_if
when
unless
complement
Sets¶
subset
proper_subset
union
intersect
diff
symmetric_diff
Numerical¶
add
sub
negate
sum
product
mul
div
power
Strings¶
Arrays¶
Maps¶
Sets¶
API Design¶
This document describes the design principles and use cases for this library.
Design Principles¶
Self-documenting¶
It should be immediately obvious what an interface does just from looking at:
The name
Usage
Ease of use¶
Prioritise ease of use. Favour decisions that maintain or improve how easy an interface is to use.
Stability¶
Backwards incompatible changes cost the user time. And probably someone’s money. Favour backwards compatability.
If we must break BC, do so in a way in which migration can be automated.
In addition, support major versions to allow for said migration.
Fail-fast¶
PHP is a dynamic language. To fail fast, we must:
Support static analysis tools
Fail-fast at run-time
This assumes extensive run-time checks of pre-conditions, post-conditions and invariats.
Example driven¶
We must first produce examples of use cases for an interface before implementing that interface. Those examples then become core to our documentation and drive the implementation.
Clear naming¶
Naming is crucial. Naming interfaces expands the implementation language. Adhere to consistent naming conventions - treat naming interfaces as the expansion of a language.
Use linguistics to assess and verify naming conventions.
Consistency¶
PHP evolved organically. And the standard library API shows for it. Fun’s raison d’etre is to smooth these inconsistencies.
Consistency forms patterns. The human mind loves patterns. Solid, enforced consistency allows users to predict usage without looking up documentation.
Immutability¶
Mutability is inherently error-prone and difficult to reason about. A utility belt library should have little need for mutability.
Type-safety¶
Use static type checkers to:
Ensure internal type safety
Correct integration with end-user type checking tools
Use Cases¶
PHP is a web language. It’s commonly used as part of the LAMP stack.
As such, PHP is typically used to:
Implement HTTP interfaces, either server-rendered or REST
Reading and writing to a database e.g implementing CRUD
Render data to some form of document, e.g HTML, JSON, XML, YAML
Transform received data for reading from and writing to a database
Validating and sanitising received input for safe use
Transform fetched data queried from a database for output
Validating and sanitising datbase data for safe output
Consuming external 3rd party APIs using SDKs and clients
Transforming values from internal representation to ones accepted by 3rd party APIs for querying or writing.
Transforming received values from 3rd party APIs to internal representations.
Validating and sanitising values read from 3rd party APIs
Writing tests that interact with DB
Writing tests that stub and fake 3rd party services
Writing tests that verify data structures
We can reduce these use cases to:
Database interaction¶
For DB interaction, an ORM or DBA layer is typically used. Eloquent, Laravel’s ORM, uses the ‘active record pattern’. On the other hand, Doctrine uses the data mapper pattern.
HTTP¶
For defining HTTP interfaces, some form of framework is typically used, allowing the user to define routes and controllers, which respond to consumer requests.
These may be REST routes or implemented to look like static pages.
API Consumption¶
When interacting with 3rd party APIs, the user typically uses an available SDK or uses a HTTP client.
3rd party SDKs typically accept data in the form of maps. In addition, they return data in maps. Even if objects are used, it is common to support access a la hash map.
Entry-points:
In response to user input
In response to a webhook
In response to a scheduled task
Examples:
Leadflo REST API endpoint for actions due
Leadflo REST API endpoint for saving a patient
Leadflo REST API endpoint for listening on tx type changes
IAS Stripe integration on subscription
IAS Stripe integration on payment failure
IAS Stripe integration on payment success
Template rendering¶
For server-rendered apps, a templating engine is typically used, as opposed (but not always) to interpolating PHP using tags in HTML documents. Input is typically provided by forms. Output typically interpolates data into a HTML template - using lists and iteration for rendering multiple records.
Serialization¶
For REST API implementation, JSON is typically used but may support XML. YAML is rarely used to implement REST APIs. Responses are typically restricted to the supported JSON data types - the complex ones being arrays and maps/objects.
In short, REST APIs serialize application data as output. But serialization is not limited to the implementation of REST APIs.
Validation¶
Validation is often supported by the framework. Frameworks typically provide a means to implement new validation rules. This often leads to string manipulations and regular expression matching and testing.
Sanitisation¶
Sanitation is often supported by and provided by frameworks. Frameworks typically provide means to implement new sanitisation rules. This involves string manipulation and regular expression matching/replacement.
Data transformation¶
Transforming values from one format to another typically involve iteration over lists of maps and the transformation of one map into another map. This may also include from one object, such as a domain model object, to a data transfer object or an entity object from a 3rd party SDK.
Configuration¶
YAML is commonly used for configuration. Symfony uses YAML. But then Symfony allows the ultimate in flexibility and thus supports multiple configuration languages.
Fun makes it easier to write functional code in PHP.
Getting Started¶
TODO: Insert getting started instructions here
Installation¶
TODO: Insert installation instructions here