Platform.sh
Presented by Larry Garfield (@Crell)
implements Huggable
We're going to have these namespace things,
let's use them the same way for a change!
(Smoke not guaranteed)
Thrown off lists.php.net, moved to Google Groups
Admitted a few new projects
Slept through 2010
Debated a lot in 2011
Renamed to Framework Interoperability Group
FIG
Actually became useful!
We're a group of established PHP projects whose goal is to talk about commonalities between our projects and find ways we can work better together.
—PHP-FIG website
PHP Standard Recommendation
Scope: Any definable standard or convention that improves collaboration and interoperability.
Projects, not people
Voted in by current voting reps
Voting representatives vote
Everything else is open to all
Random idea
PSR number assigned
Iterate and collaborate
Release Candidate
Profit!!1!
And 3 elected FIG Secretaries to do the paperwork
(Disclaimer: Author speaking!)
new \Crell\HtmlModel\Head\Link_Element();
// Results in:
include_once $some_root . '/Crell/HtmlModel/Head/Link/Element.php';
new \Crell\HtmlModel\Head\Link_Element();
// Results in:
include_once $some_root . '/Head/Link_Element.php';
The prefix is externally configured
{
"name": "crell/htmlmodel",
"autoload": {
"psr-4": {
"Crell\\HtmlModel\\": "src"
}
}
}
Always use PSR-4, not PSR-0
namespace Psr\Log;
interface LoggerInterface {
public function log($level, $message, array $context = array());
public function emergency($message, array $context = array());
public function alert($message, array $context = array());
public function critical($message, array $context = array());
public function error($message, array $context = array());
public function warning($message, array $context = array());
public function notice($message, array $context = array());
public function info($message, array $context = array());
public function debug($message, array $context = array());
}
namespace Psr\Log;
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
Based on RFC 5424
Extra metadata, including placeholders
$logger->notice("User {$username} failed to login. Hacker, maybe?");
$username = "'; DROP TABLE students; --";
$username = "<script>alert('Bobby Tables is so cute.');</script>";
Can't know output target in advance
$logger->notice("User {username} failed to login. Hacker, maybe?", [
'username' => $username,
]);
Inspired by Drupal watchdog()/t()
try {
do_something_dangerous();
}
catch (\Exception $e) {
$logger->error("Well that escalated quickly.", ['exception' => $e]);
}
Similar goal as Logging
Repository model
class MyService {
protected $pool;
public function __construct(CacheItemPoolInterface $pool) {
$this->pool = $pool;
}
public function getWidgetList() {
$item = $this->pool->getItem('widget_list');
if (!$item->isHit()) {
$value = $this->computeExpensiveWidgetList();
$item
->set($value)
->expiresAt(new DateTime('now +1 hour'));
$this->pool->save($item);
}
return $item->get();
}
}
class MyService {
protected $pool;
// ...
public function warmCache() {
foreach ($this->widgets as $widget) {
$item = $this->pool->getItem('widget-' . $widget->id());
$item->set($this->computeExpensiveValue($widget));
$this->pool->saveDeferred($item);
}
$this->pool->commit();
}
public function getWidgetInfo(array $ids) {
$list = array_map(function($id) {return 'widget-' . $id; }, $ids);
return $this->pool->getMultiple($list);
}
}
interface ImportantInterface {
public function doExpensiveStuff($param);
}
class Important implements ImportantInterface {
public function doExpensiveStuff($param) {
// ...
}
}
class CacheWrapper implements ImportantInterface {
public function __construct(CacheItemPoolInterface $pool, ImportantInterface $wrapped) {
$this->pool = $pool;
$this->wrapped = $wrapped;
}
public function doExpensiveStuff($param) {
$item = $this->pool->getItem(__CLASS__ . __METHOD__);
if (!$item->isHit()) {
$item->set($this->wrapped->doExpensiveStuff($param));
$this->pool->save($item);
}
return $item->get();
}
}
$_SERVER
HTTP Messages should be objects!
(Message passing, yo.)
$response = new Response();
$response = $response->withStatusCode(200);
$response = $response->withHeader('Content-Type', 'application/json');
$response = $response
->withHeader('Cache-Control', 'public')
->withAddedHeader('Cache-Control', 'max-age=300');
$body = new PsrFileStream('secret_plans.odt');
$response = $response->withBody($body);
$body = new StringStream($htmlData);
$response = $response->withBody($body);
$callback = function() use ($data) {
foreach ($data as $record) {
return implode(', ', $record);
}
};
$body = new CallbackStream($callback);
$response = $response->withBody($body);
URIs are way more complicated than you think
More portable and predictable than parse_url()
The most needlessly controversial specs ever
Runtime-important standards
ClassName::methodName
and ClassName::CONSTANT
You're probably doing this already.
Stylistic standards
That there is a standard matters more than what it is
PHP 7 updates coming in PSR-12...
Open alternative to Sensio Labs Security Advisory Checker
Am I vulnerable?
Yep Nope
namespace Psr\Container;
interface ContainerInterface
{
public function get(string $id);
public function has(string $id);
}
For factories and other edge cases
And delegation
namespace Psr\Link;
interface LinkInterface
{
public function getHref();
public function isTemplated();
public function getRels();
public function getAttributes();
}
namespace Psr\Link;
interface LinkCollectionInterface
{
public function getLinks();
public function getLinksByRel($rel);
}
Plus evolvable extensions
Still early, over-complicated
RequestFactoryInterface
ResponseFactoryInterface
ServerRequestFactoryInterface
StreamFactoryInterface
UploadedFileFactoryInterface
UriFactoryInterface
namespace Psr\Http\Middleware;
interface ServerMiddlewareInterface extends MiddlewareInterface
{
public function process(ServerRequestInterface $request, DelegateInterface $frame);
}
interface DelegateInterface
{
public function next(RequestInterface $request);
}
class Foo implements ServerMiddlewareInterface
{
// ... Constructor here.
public function process(ServerRequestInterface $request, DelegateInterface $delegate) {
// Pass on the request to the next middleware.
$response = $delegate->next($request);
// Or create one yourself.
return $this->responseFactory->createResponse(
$this->streamFactory->createTempStream('Hello world'),
200
);
}
}
namespace Psr\SimpleCache;
interface CacheInterface
{
public function get($key);
public function set($key, $value, $ttl = null);
public function delete($key);
public function clear();
public function getMultiple($keys);
public function setMultiple($items, $ttl = null);
public function deleteMultiple($keys);
public function exists($key);
}
Easy "wrapper" for PSR-6
The goal of FIG is to encourage collaboration
Collaboration builds interoperability
... and community
Spec | Downloads | Dependants |
---|---|---|
PSR-3 | 38 million | 1943 |
PSR-6 | 829,000 | 165 |
PSR-7 | 11 million | 711 |
(Source, Packagist.org, September 2016)
Our biggest success...
namespace Psr\Hug;
interface Huggable
{
public function hug(Huggable $h);
}
interface GroupHuggable extends Huggable
{
public function groupHug($huggables);
}
Director of Runtimes and Integrations Platform.sh
Continuous Deployment Cloud Hosting
Stalk us at @PlatformSH