This document discusses patterns, paradigms, and governance for scaling PHP applications. It provides examples of patterns like MVC and auto-wiring. Paradigms discussed include using constants, consistent coding styles, and parameter marshaling. Governance examples include database query review, tracking slow queries, and maintaining code quality. The document aims to show concrete and actionable ways that patterns, paradigms and governance can help scale PHP applications.
9. Patterns, Paradigms, and Governance
9
• How do these concepts help us scale PHP ?
• Will I see concrete actionable examples ?
• Will you show me some hardcore PHP h4x ?
13. Patterns - Accessibility
13
• An accessible pattern is one that is
intuitive, documented, and when
invoked, reads like natural language
• Reading code that follows an accessible
pattern is easier than reading code that
does not follow
14. Patterns - Repeatability
14
• The repeatability of a pattern will
ultimately decide its adoption
• If I can copy and paste, or use a scaffold
for a pattern, the pattern is repeatable
and will proliferate itself throughout the
code
15. Patterns – Clear Rationale
15
• You need to be able to explain why a
pattern was chosen
• All patterns have shortcomings – the
*why* behind the pattern’s design and
proliferation is critical in maintaining
adherence
17. Pattern Examples: Auto-wiring
17
// Autowire the model manager
public function preHandle($shapewaysModel, ModelManager $modelManager) {
// do something with the ModelManager
return parent::preHandle($shapewaysModel);
}
I can use any Manager in our
domain model by adding it to my
function signature.
18. Pattern Examples: Auto-wiring
18
public function invokeWithManagers($object, $function, $parameters)
{
$controllerClass = get_class($object);
$function = new ReflectionMethod($controllerClass, $function);
foreach ($function->getParameters() as $reflectionParameter) {
$parameterClass = $reflectionParameter->getClass();
$parameterClassName = $parameterClass->getName();
// substr is much faster than pregmatch!
if (substr($parameterClassName, -7) === "Manager") {
$parameters[] =
$this->instantiateManager($parameterClassName);
}
}
return $function->invokeArgs($object, $parameters);
}
21. 21
Paradigms – Explicit
A paradigm is explicit when the functionality
exposed can be understood from the
invoking side.
Explicit paradigms show visibly throughout a
codebase.
22. 22
Paradigms – Consistent
A paradigm is consistent when it is applied
consistently and everywhere applicable in
the code.
If your paradigm is only consistent in 60% of
your code base, chances are high that folks
will copy and proliferate code that violates
the paradigm.
23. 23
Paradigms – Provide Clear Value
It is important for the entire team to
understand and agree on the value of a
paradigm.
Paradigms can easily feel like overhead - it
is important to know *why* we choose to
adhere to a paradigm.
28. Paradigm Examples – One to Many
Making one query vs. two is often faster
SELECT umf.id
…
, mfma.model_file_material_asset_id
…
FROM udesign_model_file umf
LEFT JOIN model_file_material_asset mfma
ON mfma.model_file_id = umf.id
28
29. Paradigm Examples – One to Many
Generic function for mapping objects
/**
* Select an array of objects using the given EntityMapper
*
* @param $db the database link to use (read-only/read-write/etc)
* @param $sql the query
* @param $mapper EntityMapper
* @return array
*/
public function selectObjects($db, $sql, $mapper)
{
$db = $this->getDbLink($db);
$this->checkDBConnection($db);
// Add backtrace information to the SQL as a comment
// This helps immensely in slow query identification
$sql = $this->prependURL($sql);
if ($resultSet = $this->runQuery($sql, $db)) {
while ($row = mysql_fetch_assoc($resultSet)) {
$mapper->mapRow($row);
}
mysql_free_result($resultSet);
}
return $mapper->getResults();
}
29
30. Paradigm Examples – One to Many
Mapping results follows a paradigm
public function mapRow($row)
{
if (!isset($this->rows[$row['id']])) {
$this->rows[$row['id']] = new ModelFileEntity(
$row['id']
);
}
$modelFile = $this->rows[$row['id']];
if (isset($row['model_file_material_asset_id'])) {
$modelFileMaterialAsset = new ModelFileMaterialAsset(
$row['model_file_material_asset_id']
);
$modelFile->addModelFileMaterialAsset($modelFileMaterialAsset);
}
}
30
31. Paradigm Examples – Caching
Cache derived data
public function getPrice()
{
if ($this->getPrice_cache !== NULL) return $this->getPrice_cache;
// if override is set, use that
if (($this->getPrice_cache = $this->getPriceOverride()) !== NULL) {
return $this->getPrice_cache;
} else {
return ($this->getPrice_cache = $this->getPriceOriginal());
}
}
31
32. Paradigm Examples – Caching
Give control to the engineers
public function getCurrencyById() {
$cacheKey = 'currencyById-' .
$currencyId . '-' .
date(RoadRunnerDB::DATE_FORMAT_DAY);
$currency = null;
if(RoadRunnerLocalCache::get($cacheKey, $currency) === FALSE) {
if (($currency = $this->memcacheGet($cacheKey, 0)) === FALSE) {
$currency = $this->currencyDB->getcurrencyById($currencyId);
$this->memcacheSet($cacheKey, $currency, 0);
}
RoadRunnerLocalCache::set($cacheKey, $currency);
}
return $currency;
}
32
34. Governance
Governance is the most difficult of all the
goodness to achieve, and likely it is the most
important for performance.
If you can find a problem before it is live, you
are 10x more likely to fix it before it impacts
your users and your bottom line.
34