Något fel på min hemsida under okänd tid

Hoppsan! Idag upptäckte jag att vissa bilder i mina gallerier inte öppnade sig stora, de visade sig bara som tumnaglar. Jag vet tyvärr inte hur länge detta problemet varat, bara att det har sitt ursprung i ett serverbyte på mitt webbhotell. Det fungerade efter bytet, men någonstans mellan detta och nu, så slutade vissa länkar att fungera.

Problemet ska vara ordnat nu och jag ber om ursäkt om min hemsida under en period inte fungerat som tänkt!

Automatisk dependency injection i PHP med hjälp av typhintning

Jag har skrivit om dependency injection förut (anonyma funktioner, dependency injection och php oop kurs del 1) och nu är det faktiskt dags igen. Denna gången med en liten twist. I en del ramverk, i tex Laravel, så har man möjlighet att injicera beroenden in i andra objekt enbart genom att typhinta klassnamnet. Jag vet inte säkert om det heter så på svenska, men på engelska heter det type hinting.

Type hinting använder du genom att skriva namnet på klassen du injicerar till ditt objekt. Vanligast är att man gör det i konstruktorn (constructor injection), och då kan det se ut som så här:

function __construct(Klassnamn $klass)

I detta exemplet, så måste objektet som används som argument vara av typen Klassnamn. Om du försöker injicera ett objekt av en annan typ, så kommer php att generera ett fel. Så varför är detta så bra? Jo, för att ditt objekt ska kunna fungera, så är det beroende av denna specifika typen av objekt. Utan type hinting skulle du kunna injicera vilket objekt som helst, och du kommer säkerligen att få massa saker som inte fungerar. På detta viset vet du att ditt objekt inte kan skapas upp utan att det har alla beroenden det behöver. Det är just det som är dependency injection och type hinting i ett nötskal. Kort sagt – Använd er av det när ni programmerar objektorienterat  php! 🙂

Men hursomhelst, så måste ett objekt som behöver injiceras senare fortfarande skapas. Många dependency injection containers som finns på nätet löser detta, men jag skulle vilja visa ett sätt som det kan göras på för att visa hur det hela kan fungera.

Observera/Disclaimer Detta är inte är någon kod jag vill ni ska använda i skarpt läge, men det kan kanske vara intressant att läsa igenom och kanske inspireras av?

Koden till en förenklad Service Container

Låt oss se hur den ser ut:

<?php
class ServiceContainer
{
    /* @var Lagrade objekt */
    private $instances;
 
    /**
     * Skapa upp servicecontainern och lagra sig själv.
     */
    public function __construct()
    {
        $this->add($this);
    }
 
    /**
     * Lägg till ett objekt.
     * @param object $instance
     */
    public function add($instance)
    {
        $this->instances[get_class($instance)] = $instance;
    }
 
    /**
     * Hämta ett objekt.
     * @param string $name Klassnamn.
     * @return object
     */
    public function get($name)
    {
        // Använd reflection för att undersöka klassen.
        $reflector = new \ReflectionClass($name);
 
        // Objekt av typen finns redan lagrad.
        if (isset($this->instances[$name])) {
            return $this->instances[$name];
        }
 
        // Skapa en ny instans.
        if ($reflector->getConstructor()) {
            $injections = $this->getInjections($reflector);
            $instance = $reflector->newInstanceArgs($injections);
        } else {
            $instance = $reflector->newInstance();
        }
 
        // Lagra och returnera objektet.
        $this->add($instance);
 
        return $instance;
    }
 
    /**
     * Hämta konstruktorns parametrar.
     * @param ReflectionClass $reflector
     * @return array
     */
    private function getInjections($reflector)
    {
        $parameters = $reflector->getConstructor()->getParameters();
        foreach ($parameters as $parameter) {
            $name = $parameter->getClass()->name;
            $injections[] = $this->get($name);
        }
 
        return $injections;
    }
}

Låt oss gå uppifrån och ner för att förklara hur det fungerar.

Den enda variabeln (instances) vi behöver är för att lagra objekt som redan finns uppskapade. Objekten är delade, d.v.s. att endast ett objekt av samma typ kan existera i samma container.

Konstruktorn (__construct) är enkel. Det enda den gör är att lägga till sig själv i containern.

Metoden add() är lika enkel den. Där kan du manuellt lägga till ett objekt till containern om du skulle behöva. Nyckeln som lagras internt blir klassnamnet.

Nu börjar det bli intressant. Metoden get() används för att skapa och returnera ett efterfrågat objekt från containern. Om en instans av rätt klass redan finns lagrad, så returneras den direkt. Vi använder oss av Reflections för att undersöka den efterfrågade klassen. Om klassen har en konstruktor, undersöks den och vi kan avgöra om den har några argument eller inte. Om konstruktorn tar argument, så kallar vi på metoden getInjections() för att hämta dessa. En ny instans skapas med hjälp av newInstanceArgs(), eller newInstance(). Slutligen lagras instansen i containern och så returneras den tillbaka.

Metoden getInjections() används slutligen för att skapa upp objekt som behöver injiceras till en konstruktor för att ett objekt ska kunna skapas upp. Metoden loopar igenom alla argument och skapar upp objekt med hjälp av get() och returnerar dem tillbaka i en array som kan användas när det beroende objektet sedan skapas upp.

Ett exempel:

// Exempel:
class Engine {}
class Tires {}
class Car {
    public function __construct(Engine $engine, Tires $tires) {}
}
class Owner {
    public function __construct(Car $car, ServiceContainer $sc) {}
}
 
$c = new ServiceContainer();
$owner = $c->get('Owner');
 
var_dump($owner);
var_dump($c);

Först några klasser som vi kan testa att skapa instanser utav. Engine och Tires är enkla klasser som inte har någon konstruktor och således inte har några beroenden heller. Klassen Car däremot är beroende av både Engine och Tires för att fungera. Lägg märke till type hintingen av dessa två klasser i konstruktorn.

Klassen Owner vill ha en Car för att bli tillfredställt och bara för att vi ska se att det fungerar, så slänger vi in även containern som ett beroende. Ett varningens ord här dock – Det är generellt sett inte någon bra idé att skapa ett beroende av en container i en klass. Även om vi har type hintat containern, så vet vi inte om alla containern innehåller alla de objekt koden förväntar sig. Det är bättre att type hinta respektive klass som ett objekt är beroende av i konstruktorn, vilket ju är just det som hela detta inlägget faktiskt går ut på!

Så när vi anropar ServiceContainerns metod get(), så skapas samtliga objekt upp som Owner är beroende av. Genom att dumpa ut $owner och $c så ser vi just detta. Ownerobjektet är skapat och $c, dvs servicecontainern, innehåller alla de objekt som Owner är beroende av:

object(Owner)[5]
object(ServiceContainer)[1]
  private 'instances' => 
    array (size=5)
      'ServiceContainer' => 
        &object(ServiceContainer)[1]
      'Engine' => 
        object(Engine)[9]
      'Tires' => 
        object(Tires)[10]
      'Car' => 
        object(Car)[8]
      'Owner' => 
        object(Owner)[5]

Sammanfattning

Det är inte alla tillfällen som lämpar sig för en sådan här (enkel) lösning. Det finns några stora nackdelar. Till exempel så kan containern bara leverera objekt som har argument med type hintade klasser. Och dessa i sin tur måste också bestå av desamma. Det går inte i denna implementationen att använda sig av argument som tar strängar, arrays eller annat.

Den klarar inte heller av att injicera objekt där man använder interface som typhintning, vilket till viss del motverkar (subtype) polymorfism, vilket egentligen är önskvärt när man programmerar objektorienterat.

Den hanterar endast injektioner till konstruktorn. I vissa situationer så kan injektioner till enskilda metoder också vara praktiskt (s.k. method injection). Om det där tvistar de lärde, men jag föredrar att i största möjliga mån hålla mig till konstruktorn.

Containern lämpar sig helt enkelt bäst till ändamål där man automatiskt behöver skapa beroenden och eventuell input till respektive objekt sker först efter instansieringen. Alternativt beroende av objekt som kan skapas upp mer eller mindre manuellt innan den automatiska instansieringen. Tänk er en controller i MVC som väljs genom URL, eller någon annan routing, och som behöver en eller flera modeller för att kunna göra sitt jobb. I ett automatiserat flöde, så kan vi inte manuellt skapa upp dessa objektberoenden, utan vi måste förlita oss till någon form av objektfabrik, såsom denna service containern.

Hoppas ni förstår kraften med denna typen av funktionalitet och kanske söker er vidare till någon av de mer robusta och testade lösningar som finns där ute. Lösningar som många gånger tar upp de problem som jag nämnt ovan. Sök gärna mer information på er favoritsökmotor. Använd te.x. ”dependency injection container php” som sökord.

Må bäst, tills nästa gång! 🙂

Installera (och använd) php’s beroendehanterare composer i Windows 8

Traditionellt sett så har Microsoft Windowsanvändare de senaste åren varit ganska motvilliga att använda allt annat än det grafiska gränssnittet. Men som webb/php-utvecklare idag, så är det mycket vunnet att kunna använda kommandotolken åtminstone till det allra enklaste. En av anledningarna är composer.

Composer logoComposer är en programvara som hjälper dig att handskas med beroenden i din kod. Genom att definiera vilka beroenden, eller paket som du behöver i ditt projekt, så kan du enkelt ladda ner dem och hålla dem uppdaterade via enkla kommandon. Du får dessutom en autoloader på köpet, som laddar in klasser när du använder dem utan att du behöver använda include eller require i php.

De flesta stora php-ramverk använder sig idag av composer som standard. Och de som inte gör det, borde faktiskt ta sig en allvarlig funderare på att böra göra så.

Installationen av composer har tidigare varit lite bökig i windows-miljö för den ovane, men nu så har installationsprocessen blivit så enkel den bara kan bli.

Installera composer

Gå in på composers hemsida, https://getcomposer.org/ , klicka på download i menyn och ladda ner installationsfilen (Composer-Setup.exe) under överskriften Windows installer.

Kör filen och följ instruktionerna. Standardinställningar är okej att använda. Composer måste veta var php ligger installerat och kommer att fråga efter detta under installationen. På min maskin, med WAMP installerat som lokal server, ser det ut som nedan:

Sökväg till php i composerinstallation

Fortsätt att följa instruktionerna, så ska det snart vara klart!

När installationen är klar kan du kontrollera att allt fungerar genom att öppna en kommandotolk (tryck på windows-tangenten, skriv ”cmd” följt av enter). Om allt fungerar så ska du kunna köra kommandot ”composer” var som helst i mappstrukturen, och resultatet kommer att se ut ungefär som det nedan:

composer i kommandotolken

Där ser du nu vilka argument du kan använda för composer. Läs mer på deras hemsida om alternativen.

Använda composer i ett nytt projekt

Att installera composer är en sak, men att använda den är en annan. Även om dokumentationen är ganska tydlig, så känner jag att ett snabbt exempel på användning måste finnas med i mitt inlägg.

Packagist, är den hemsida som innehåller de officiella paket som composer använder sig av. Där kan du enkelt söka dig fram till ett intressant paket som du skulle vilja testa. Varför inte monolog, ett paket för att logga händelser till fil?

Skapa en ny mapp/projekt på sin webbserver och lägg en ny fil, composer.json i den, med följande innehåll:

{
   "require": {
      "monolog/monolog": "1.12.*@dev"
   }
}

Gå nu in i din nya mapp i kommandotolken och kör ”composer install” (utan citattecken), så kommer monolog att laddas ner och läggas till i ditt projekt. Composer löser dessutom själv monologs beroenden, så att alla paket den är beroende av också laddas ner.

(Har du inte git installerat på din maskin så kommer du att få lite varningar, men det kommer att fungera ändå).

Nu har en ny mapp, ”vendor”, lagts in där alla paket finns lagrade. En autoload-fil har automatiskt skapats som håller reda på vart filerna ligger, så att de kan hittas av composer när du anropar dem. Detta är alltså den enda fil du behöver ladda in för att sedan använda vilket paket som helt som du lagt in i composer.json-filen. Skapa en index.php i roten av ditt projekt för att testa:

<?php
require 'vendor/autoload.php';

$log = new Monolog\Logger('name');
var_dump($log);

När du kör koden, så kommer du att se din nyskapade instans av Monolog-klassen, färdig att användas.

För att lägga till fler paket till ditt projekt, så lägger du till ett nytt beroende i composer.json och kör ”composer update”, så läggs de nya filerna in i projektet!

Gör valet att följa standarder i PHP

PHP Framework Interop Group är en  sammansatt grupp av medlemmar ur många av de allra största ramverken i PHP. Tanken med gruppen är att de ska besluta om gemensamma kodstandarder i PHP-världen. Och med så många både stora och lite mindre aktörer som medlemmar så har (faktiskt) php-fig och deras standarder PSR (Proposed Standards Recommendation) blivit mer än väl accepterat.

Fördelen med att följa en standard är många. Det kan t.ex. handla om allt från att det blir lättare att läsa kod eftersom du är van vid utseendet, till att en standardiserad pakethantering gör det lättare att använda 3’e-parts kod i ditt egna projekt.

Fördelarna är kanske inte så stora om du bara sitter hemma i kammaren och programmerar endast själv, och för dina egna ändamål. Men om du har minsta intresse av att så småningom blanda in flera programmerare, eller kanske publicera ditt projekt för att andra ska kunna använda det, då blir det genast mycket viktigare.

För att inte tala om den dagen du blir anställd programmerare och kan nämna att du följer standarder! Då är det bra att var förberedd och inte så smart att säga ”jag har alltid gjort på detta viset, och kommer att fortsätta med det” 😉

Nedan följer en länkar och en kort beskrivning av några standarder:

PSR-0 beskriver standarder för autoloading av klasser, och därmed även filnamn. Det finns även exempel på hur en autoloader kan se ut med vanlig autoload och med SplClassLoader, som är att föredra framför de två.

PSR-1 beskriver enklare kodstandarder såsom php-taggar, teckenkodning, klass- och metodnamn, konstanter och namespaces.

PSR-2 tar över där PSR-1 slutar och beskriver detaljer kring kodstandarden. Bl.a. beskrivs när radbrytningar och mellanslag ska ske eller inte ske,  var klamrar och paranteser ska läggas, hur indentering i koden ska vara och mycket mer. Detta är den mest utförliga standarden när det gäller ”utseendet” på din kod.

PSR-3 beskriver hur ett interface för loggning av varningar och fel bör se ut. Exempelkod finns även här.

PSR-4 fortsätter att beskriva och komplettera PSR-0, dvs hur autoloadern ska fungera. Nämner även Composer och pakethantering.

 PSR-5 är ännu inte en accepterad standard, men mycket tyder på att den inte kommer att ändra sig så väldigt mycket innan den accepteras. PSR-5 tar upp det som kallas för docblocks, en standard för att kommentera din kod. Docblocks används bland annat av phpDocumentor för att automatiskt generera dokumentation.

Semantic Versioning 2.0.0 är inte en del av php-fig, men beskriver hur du bör tänka när du sätter versioner på ditt projekt.

 

Använda Laravels Eloquent ORM i Up MVC

Laravel logoDet senaste halvåret så har jag använt Laravel mycket i arbetet och har verkligen fattat tycke för det ramverket. En av de bästa delarna av Laravel är Eloquent ORM (Object Relational Mapping) som används för att enklare hantera databaser och data i dessa. En mycket väl fungerande implementation av Active Record!

UpMVC

Med intåget av Composer i UpMvc, så är det nu möjligt att göra saker som tidigare vad mycket besvärligare. Det är faktiskt möjligt att börja använda Eloquent för modeller om du så vill. Det kräver dock att en del andra beroenden skapas upp för att allt ska fungera, vilket enklast läggs in i en basmodell som vi sedan enkelt kan ärva i våra egna modeller.

Men först ska Eloquent installeras.

Installera Eloquent ORM i Up MVC

(Detta förutsätter att du har en fungerande installation av Composer installerat på din maskin. Läs på deras hemsida om du inte redan har det installerat).

Uppdatera filen composer.json så att stycket med require ser ut som nedan:

    "require": {
        "php": ">=5.3.0",
        "illuminate/database": "*"
    }

Öppna kommandotolken, gå in i UpMVC’s mapp och kör sedan kommandot composer update. Efter en lite stund kommer Eloquent att ha laddats ner från Packagist.org, installerats i vendor-mappen och nya autoload-filer har genererats automatiskt.

Skapa en basmodell

För att kunna använda Eloquent i modeller, så kräver det att vissa beroenden är uppsatta ordentligt. Laravel görs så klart detta bakom kulisserna, men eftersom Up MVC inte är Laravel så får vi göra det själva. Däremot är det precis som själva installationen ett engångsjobb. Spara följande modell i filen App/Model/Eloquent.php:

<?php
namespace App\Model;
 
use UpMvc;
use UpMvc\Container as Up;
 
/**
 * Sätt upp Laravel Eloquent ORM i UpMvc2.
 *
 * Glöm inte att UpMvc's modeller använder namespace App\Model, så sätt
 * App\Model\ framför klassnamn när du sätter upp din modells relationer.
 * 
 * @package UpMvc2
 * @author  Ola Waljefors
 * @version 2014.2.1
 * @link    http://laravel.com/docs/eloquent
 */
class Eloquent extends \Illuminate\Database\Eloquent\Model
{
    /** @var array Standardinställningar för Eloquent ORM. */
    protected $settings = array(
        'charset'   => 'utf8',
        'collation' => 'utf8_general_ci'
    );
 
    /**
     * Lägg till projektets inställningar.
     */
    public function __construct()
    {
        // Kör ärvd konstruktor.
        parent::__construct();
 
        $settings = array(
            'driver'   => Up::db_engine(),
            'host'     => Up::db_host(),
            'username' => Up::db_user(),
            'password' => Up::db_password(),
            'database' => Up::db_name()
        );
        $this->settings = array_merge($this->settings, $settings);
 
        // Initiera.
        $this->bootstrap();
    }
 
    /**
     * Initiera Eloquent-objekt.
     */
    private function bootstrap()
    {
        $container  = new \Illuminate\Container\Container();
        $factory    = new \Illuminate\Database\Connectors\ConnectionFactory($container);
        $connection = $factory->make($this->settings);
        $resolver   = new \Illuminate\Database\ConnectionResolver();
        $resolver->addConnection('default', $connection);
        $resolver->setDefaultConnection('default');
        \Illuminate\Database\Eloquent\Model::setConnectionResolver($resolver);
    }
}

Det vi gör i denna modellen är att hämta de vanliga inställningarna för databaser  i App/config.php och sedan skapa upp alla beroenden. Genom att ärva denna modellen i dina kommande så har du nu full Eloquent-funktionalitet i ditt eget Up MVC-projekt.

Exempel på modeller

Om vi tänker oss en blogg där varje inlägg sparas i tabellen posts och författaren till samma inlägg postas i tabellen authors, så skulle modellerna för detta se ut ungefär som nedan:

Fil: App/Model/Post.php

<?php
namespace App\Model;
 
class Post extends Eloquent
{
    protected $table = 'posts';
 
    public function author()
    {
        return $this->belongsTo('App\Model\Author');
    }
}

Fil: App/Model/Author.php

<?php
namespace App\Model;
 
class Author extends Eloquent
{
    protected $table = 'authors';
 
    public function posts()
    {
        return $this->hasMany('App\Model\Author');
    }
}

Summering

Även om det bevisligen är möjligt så lämnar jag det upp till er att avgöra om det är en bra idé eller inte att använda Eloquent ORM utanför Laravel. Men hur som helst så visar detta lite på hur flexibelt det kan vara att använda Composer för sina projekt. Packagist.org (vilket är Composers huvudsakliga repository) har tusentals paket som man kan använda i alla Composer-kompatibla projekt, det är bara att välja och vraka!

Hoppas att ni blivit inspirerade?

 

Nästa sida »