<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>psr Archivi - Cesare Bordi | Innovation Manager &amp; Back-end Developer</title>
	<atom:link href="https://www.cesarebordi.it/tag/psr/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cesarebordi.it/tag/psr/</link>
	<description>Innovare con soluzioni software efficaci e gioco di squadra</description>
	<lastBuildDate>Tue, 24 Nov 2020 07:48:42 +0000</lastBuildDate>
	<language>it-IT</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.2</generator>

<image>
	<url>https://www.cesarebordi.it/wp-content/uploads/2016/02/CB-logo-88x88.png</url>
	<title>psr Archivi - Cesare Bordi | Innovation Manager &amp; Back-end Developer</title>
	<link>https://www.cesarebordi.it/tag/psr/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PSR-7 Http Message: standard php per Request e Response.</title>
		<link>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/</link>
					<comments>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/#respond</comments>
		
		<dc:creator><![CDATA[cesarebordi]]></dc:creator>
		<pubDate>Wed, 23 Sep 2020 07:27:42 +0000</pubDate>
				<category><![CDATA[Lezioni]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[best practice]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fig]]></category>
		<category><![CDATA[phpfig]]></category>
		<category><![CDATA[psr]]></category>
		<category><![CDATA[psr-7]]></category>
		<category><![CDATA[psr7]]></category>
		<category><![CDATA[standard]]></category>
		<category><![CDATA[web developer]]></category>
		<category><![CDATA[webservice]]></category>
		<guid isPermaLink="false">https://www.cesarebordi.it/?p=1273</guid>

					<description><![CDATA[<p>PSR-7 Http Message del PHP-FIG propone interfacce php standard per rappresentare i messaggi Http di Request e Response.</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/">PSR-7 Http Message: standard php per Request e Response.</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>PSR-7 Http Message</strong> del PHP-FIG propone interfacce <strong>php</strong> standard per rappresentare i <strong>messaggi Http</strong> di <strong>Request</strong> e <strong>Response</strong> oltre ad analizzarne il contenuto.</p>



<blockquote class="wp-block-quote"><p>HTTP messages are the foundation of web development.</p></blockquote>



<p>Standardizzare questo aspetto è importantissimo poiché i messaggi Http sono le fondamenta dello sviluppo web. I browser ed i client come cURL inviano <strong>richieste Http</strong> al server che fornisce un&#8217;adeguata <strong>risposta Http</strong>.</p>



<p>Di seguito analizzeremo le interfacce proposte dal <a href="https://www.php-fig.org/psr/psr-7/" target="_blank" rel="noreferrer noopener">PSR-7</a> che rappresentano astrazioni dei messaggi Http e degli elementi che li compongono. Per il significato delle parole chiave presenti nell&#8217;articolo si rimanda alle <a href="https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/#note" target="_blank" rel="noreferrer noopener">note dell’articolo sul PSR-1</a>.</p>



<h2 class="wp-block-heading">Http Request</h2>



<p>Iniziamo esaminando il contenuto di una <strong>Http Request</strong>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; gutter: false; title: ; notranslate">
POST /path HTTP/1.1
Host: example.com

foo=bar&amp;baz=bat
</pre></div>


<p>La prima riga,  detta &#8220;request line&#8221;, contiene il <strong>metodo della richiesta Http</strong>, il <strong>target della richiesta Http</strong>, solitamente una URI assoluta o un percorso sul server web, la <strong>versione del protocollo Http</strong> utilizzato. A questo seguono una o più <strong>intestazioni Http</strong>, una riga vuota ed il <strong>corpo del messaggio</strong>.</p>



<h2 class="wp-block-heading">Http Response</h2>



<p>Esaminiamo ora il contenuto di una <strong>Http Response</strong>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; gutter: false; title: ; notranslate">
HTTP/1.1 200 OK
Content-Type: text/plain

This is the response body
</pre></div>


<p>La prima riga di una <strong>Http Response</strong>, detta &#8220;status line&#8221;, contiene la <strong>versione del protocollo Http</strong>, il <strong>codice di stato Http</strong> ed una <strong>descrizione comprensibile</strong> del codice di stato. Come per il messaggio di richiesta, questa riga è seguita da una o più <strong>intestazioni Http</strong>, una riga vuota ed il <strong>corpo del messaggio</strong>.</p>



<h2 class="wp-block-heading">PSR-7: specifiche</h2>



<h3 class="wp-block-heading">Messaggi Http</h3>



<p>Un <strong>messaggio Http</strong> è una richiesta da un client ad un server o una risposta da un server ad un client. PSR-7 definisce le rispettive interfacce per i messaggi Http: <strong><em><code>Psr\Http\Message\RequestInterface</code></em></strong> e <strong><em><code>Psr\Http\Message\ResponseInterface</code></em></strong>.</p>



<p>Entrambe estendono <strong><em><code>Psr\Http\Message\MessageInterface</code></em></strong>.<br />Mentre <strong><em><code>&lt;a href=&quot;#MessageInterface&quot;&gt;Psr\Http\Message\MessageInterface&lt;/a&gt;</code></em></strong> <strong>PUÒ essere implementato</strong> direttamente, gli implementatori <strong>DOVREBBERO implementare</strong> <strong><em><code>Psr\Http\Message\RequestInterface</code></em></strong> e <strong><em><code>Psr\Http\Message\ResponseInterface</code></em></strong>.<br />Per migliorare la lettura dell&#8217;articolo, da qui in avanti verrà omesso il namespace <em><code>Psr\Http\Message</code></em> per riferirsi a queste interfacce.</p>



<h3 class="wp-block-heading">HTTP Headers</h3>



<h4 class="wp-block-heading">Nomi case-insensitive nei campi di intestazione.</h4>



<p>I <strong>messaggi Http</strong> possono includere vari campi nell&#8217;intestazione (header) <strong>senza distinzione tra maiuscole e minuscole</strong>. Allo stesso modo dovranno essere recuperate dalle classi che implementano <code>&lt;strong&gt;&lt;em&gt;&lt;a href=&quot;#MessageInterface&quot;&gt;MessageInterface&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;</code>. <br />Ad esempio, il recupero dell&#8217;intestazione <code>foo</code> restituirà lo stesso risultato del recupero dell&#8217;intestazione <code>FoO</code>. Allo stesso modo, l&#8217;impostazione dell&#8217;intestazione <code>Foo</code> sovrascriverà qualsiasi valore di intestazione <code>foo</code> precedentemente impostato.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$message = $message-&gt;withHeader('foo', 'bar');

echo $message-&gt;getHeaderLine('foo');
// Outputs: bar

echo $message-&gt;getHeaderLine('FOO');
// Outputs: bar

$message = $message-&gt;withHeader('fOO', 'baz');

echo $message-&gt;getHeaderLine('foo');
// Outputs: baz
</pre></div>


<p>Nonostante le intestazioni possano essere recuperate senza distinzione tra maiuscole e minuscole, <strong>il case originale DEVE essere rispettato</strong> nell&#8217;implementazione, in particolar modo quando viene recuperato con <code>getHeaders()</code>. Questo perché applicazioni Http non conformi possono dipendere da un determinato caso.</p>



<h4 class="wp-block-heading">Campi di intestazione con valori multipli</h4>



<p>Per gestire campi di intestazione con più valori e fornire una migliore flessibilità nella gestione, le intestazioni possono essere recuperate da un&#8217;istanza di <code>&lt;strong&gt;&lt;em&gt;MessageInterface&lt;/em&gt;&lt;/strong&gt;</code> come array o stringa. Nel primo caso useremo <code>&lt;strong&gt;getHeader()&lt;/strong&gt;</code>, nel secondo <code>&lt;strong&gt;getHeaderLine()&lt;/strong&gt;</code>. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$message = $message
    -&gt;withHeader('foo', 'bar')
    -&gt;withAddedHeader('foo', 'baz');

$header = $message-&gt;getHeaderLine('foo');
// $header contiene: 'bar,baz'

$header = $message-&gt;getHeader('foo');
// &#x5B;'bar', 'baz']
</pre></div>


<p>Da notare che non tutti i valori di intestazione possono essere concatenati con la virgola (es: Set-Cookie). In questo caso gli utilizzatori <strong>DOVREBBERO usare metodo <code>getHeader()</code></strong> per recuperare tali intestazioni multivalore.</p>



<h4 class="wp-block-heading">Intestazione &#8220;Host&#8221;</h4>



<p>Nelle richieste, l&#8217;intestazione <code>Host</code> riporta l&#8217;host dell&#8217;URI, nonché l&#8217;host utilizzato per stabilire la connessione Tcp. Le specifiche del protocollo Http consentono però all&#8217;intestazione <code>Host</code> di differire da entrambi. Le implementazioni, se non viene fornita alcuna intestazione <code>Host</code>, <strong>DEVONO tentare di impostarla da un URI predefinito</strong> .</p>



<p><code>&lt;strong&gt;RequestInterface :: withUri (UriInterface $uri, $preserveHost = false)&lt;/strong&gt;</code>, per impostazione predefinita, sostituirà l&#8217;intestazione Host della richiesta restituita con quella dell&#8217;oggetto di tipo <code>&lt;strong&gt;UriInterface&lt;/strong&gt;</code> passatogli. Per mantenere il valore originale basterà passare <code>true</code> al secondo argomento (<code>$preservHost</code>). Ciò manterrà invariata l&#8217;intestazione Host a patto che il messaggio ne contenga una.</p>



<p>Questa tabella mostra cosa restituirà <code>getHeaderLin(&#039;Host&#039;)</code> per una richiesta restituita da <code>withUri()</code> con l&#8217;argomento <code>$preservHost</code> impostato su <code>true</code> in varie richieste iniziali e URI.</p>



<table>
  <thead>
    <tr>
      <th>Request Host header<sup>1</sup></th>
      <th>Request host component<sup>2</sup></th>
      <th>URI host component<sup>3</sup></th>
      <th>Result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>’’</td>
      <td>’’</td>
      <td>’’</td>
      <td>’’</td>
    </tr>
    <tr>
      <td>’’</td>
      <td>foo.com</td>
      <td>’’</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>’’</td>
      <td>foo.com</td>
      <td>bar.com</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>foo.com</td>
      <td>’’</td>
      <td>bar.com</td>
      <td>foo.com</td>
    </tr>
    <tr>
      <td>foo.com</td>
      <td>bar.com</td>
      <td>baz.com</td>
      <td>foo.com</td>
    </tr>
  </tbody>
</table>



<ol><li>Valore dell&#8217;intestazione host prima dell&#8217;operazione.</li><li>Componente host dell&#8217;URI composto nella richiesta prima dell&#8217;operazione.</li><li>Componente host dell&#8217;URI settato tramite <code>withUri()</code>.</li></ol>



<h3 class="wp-block-heading">Streams</h3>



<p>I messaggi Http sono costituiti da una riga iniziale, alcune intestazioni ed un corpo che può essere anche molto grande. Rappresentare il body di un messaggio come una stringa potrebbe consumare molta memoria fino a precludere la possibiltà di lavorare con body di grandi dimensioni. <code>&lt;strong&gt;StreamInterface&lt;/strong&gt;</code> viene utilizzato proprio per nascondere i dettagli di implementazione quando un flusso di dati viene letto o scritto. Per le situazioni in cui una stringa sarebbe un&#8217;implementazione del messaggio appropriata, è possibile utilizzare flussi incorporati come <code>php://memory</code> e <code>php://temp</code>.<br /><br /><strong><code>StreamInterface</code></strong> espone diversi metodi che consentono di leggere, scrivere e scorrere gli stream in modo efficace.<br /><br />Gli stram espongono le loro capacità utilizzando tre metodi: <strong><code>isReadable()</code></strong>, <code>&lt;strong&gt;isWritable()&lt;/strong&gt;</code> e <code>&lt;strong&gt;isSeekable()&lt;/strong&gt;</code>. Gli oggetti che vogliono utilizzare uno stream possono utilizzare questi metodi per determinare se è in grado di soddisfare determinati requisiti.<br /><br />Ogni istanza di uno stream avrà diverse funzionalità: può essere di sola lettura, di sola scrittura o di lettura/scrittura. Può consentire un accesso casuale arbitrario (ricerca in avanti o indietro in qualsiasi posizione) o solo accesso sequenziale come nel caso di socket, pipe, o callback-based stream.<br /><br />Infine, <strong><code>StreamInterface</code></strong> definisce un metodo <strong><code>__toString()</code></strong> per recuperare o inviare l&#8217;intero contenuto del corpo in una sola volta.<br /><br />A differenza delle interfacce di Request e Response, <strong><code>StreamInterface</code></strong> interagisce con gli stream che, per loro natura, possono mutare durante il loro utilizzo. La raccomandazione di Php-Fig è di utilizzare flussi di sola lettura per le richieste lato server e le risposte lato client.</p>



<h3 class="wp-block-heading">Target della richiesta ed URI</h3>



<p>Secondo lo standard <a rel="noreferrer noopener" href="https://tools.ietf.org/html/rfc7230" target="_blank">RFC 7230</a> i messaggi di richiesta contengono uno dei seguenti tipi di &#8220;target&#8221;:</p>



<ul><li><strong>origin-form</strong>: costituito da <strong>percorso</strong> e, se presente, <strong>stringa della query</strong>. È solitamente definito come un URL relativo. I messaggi trasmessi via Tcp sono tipicamente di tipo <em>origin-form</em>; i dati di <em>scheme</em> e <em>authority</em> sono presenti tramite variabili CGI.</li><li><strong>absolute-form</strong>: costituito da <strong>scheme</strong>, <strong>authority</strong> (“[user-info@]host[:port]”, dove gli elementi tra parentesi sono facoltativi), <strong>percorso</strong> (se presente), <strong>stringa della query</strong> (se presente) e<strong> fragment</strong> ( se presente). È solitamente definito come un URI assoluto ed è l&#8217;unico che consente di specificare una URI come descritto nel <a rel="noreferrer noopener" href="https://tools.ietf.org/html/rfc3986" target="_blank">RFC 3986</a>. Questo modulo è comunemente usato quando si effettuano richieste ai proxy Http</li><li><strong>authority-form</strong>: costituito dalla sola <strong>authority.</strong> È solitamente utilizzato nelle CONNECT Request per stabilire una connessione tra un client Http e un server proxy.</li><li><strong>asterisk-form</strong>: costituito unicamente dalla <strong>stringa asterisco</strong> ( &#8221; * &#8221; ). È solitamente utilizzato con il <strong>metodo OPTIONS</strong> per determinare le capacità generali di un server web.</li></ul>



<p>Oltre a questi target di richiesta, c&#8217;è spesso un &#8220;URL effettivo&#8221; che è separato dal target di richiesta. L&#8217;URL effettivo non viene trasmesso all&#8217;interno di un messaggio Http, ma viene utilizzato per determinare il protocollo (http / https), la porta e l&#8217;host-name per effettuare la richiesta.</p>



<p>L&#8217;URL effettivo è rappresentato da <code>&lt;strong&gt;UriInterface&lt;/strong&gt;</code>. <code>UriInterface</code> rappresenta gli URI Http e Https fornendo i metodi per interagire con le varie parti dell&#8217;URI evitendo un&#8217;analisi ripetuta dell&#8217;URI. Specifica inoltre un metodo <code>__toString()</code> per rappresentare la URI come stringa.</p>



<p>Quando si recupera la destinazione della richiesta con <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code>, per impostazione predefinita questo metodo utilizzerà l&#8217;oggetto URI ed estrarrà tutti i componenti necessari per costruire l&#8217;origin-form che è il request-target più comune.</p>



<p>Se si desidera utilizzare uno degli altri tre tipi di target o se l&#8217;utente desidera sovrascrivere esplicitamente il target della richiesta si utilizzerà il metodo <code>&lt;strong&gt;withRequestTarget()&lt;/strong&gt;</code>. La chiamata a questo metodo non influisce sull&#8217;URI, poiché viene restituito da <code>&lt;strong&gt;getUri()&lt;/strong&gt;</code>.</p>



<p>Ad esempio, un utente potrebbe voler effettuare una richiesta in formato asterisco a un server:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$request = $request
    -&gt;withMethod('OPTIONS')
    -&gt;withRequestTarget('*')
    -&gt;withUri(new Uri('https://example.org/'));
</pre></div>


<p>L&#8217;esempio creerebbe questo tipo di richiesta Http:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
OPZIONI * HTTP / 1.1
</pre></div>


<p>Il client Http sarà poi in grado di utilizzare l&#8217;URL effettivo (<code>getUri()</code>) per determinare il protocollo, l&#8217;host-name e la porta Tcp.</p>



<p>Un client Http <strong>DEVE</strong> ignorare i valori di <code>&lt;strong&gt;Uri::getPath()&lt;/strong&gt;</code> e <code>&lt;strong&gt;Uri::getQuery()&lt;/strong&gt;</code> ed utilizzare il valore restituito da <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code> che concatena questi due valori.</p>



<p>I client che scelgono di non implementare 1 o più dei 4 request-target form, <strong>DEVONO</strong> comunque utilizzare <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code>. Questi client <strong>DEVONO</strong> rifiutare <strong>request-target</strong> che non supportano e <strong>NON DEVONO</strong> utilizzare i valori di <code>&lt;strong&gt;getUri()&lt;/strong&gt;</code>.</p>



<p><code>&lt;strong&gt;RequestInterface&lt;/strong&gt;</code> fornisce metodi per recuperare il target della richiesta o creare una nuova istanza specificando il target. Per impostazione predefinita, se non viene specificato il request-target, <code>&lt;strong&gt;getRequestTarget()&lt;/strong&gt;</code> restituirà l&#8217;origin-form della URI composta o &#8221; / &#8221; se non è stata composta una URI. <strong><code>withRequestTarget($requestTarget</code>)</strong> crea una nuova istanza con il request-target specificato ed è utile per creare connessioni verso un server.</p>



<h3 class="wp-block-heading">Richieste Server-side</h3>



<ul><li><code>&lt;strong&gt;RequestInterface&lt;/strong&gt;</code> permette di rappresentare un messaggio di richiesta Http, ma le richieste lato server side richiedono un&#8217;attenzione particolare. I processi server-side devono tener conto della Common Gateway Interface (CGI) e dell&#8217;interazione di PHP con essa attraverso le sue via Server API (SAPI) . PHP ci fornisce una semplificazione per la gestione degli input attraverso variabili superglobali:</li><li><code>&lt;strong&gt;$_COOKIE&lt;/strong&gt;</code>: deserializza e fornisce un accesso ai cookie Http.</li><li><code>&lt;strong&gt;$_GET&lt;/strong&gt;</code>: deserializza e fornisce un accesso agli argomenti della query string.</li><li><strong><code>$_POST</code></strong>: deserializza e fornisce un accesso per i parametri inviati tramite. Post Http. Può essere considerato il risultato dell&#8217;analisi del message body.</li><li><strong><code>$_FILES</code></strong>: fornisce metadati relativi ai caricamenti dei file.</li><li><strong><code>$_SERVER</code></strong>: fornisce l&#8217;accesso alle variabili d&#8217;ambiente CGI / SAPI che includono il metodo di richiesta, lo schema di richiesta, l&#8217;URI della richiesta e le intestazioni.</li></ul>



<p><strong><code>ServerRequestInterface</code></strong> estende <strong><code>RequestInterface</code></strong> per fornire un&#8217;astrazione su questi variabili superglobali riducendo l&#8217;accoppiamento.<br /><br />La richiesta server-side fornisce una proprietà aggiuntiva,  gli &#8220;attributi&#8221;, che consentono di esaminare, scompore e cercare match in modo da interpretare la richiesta in base alle specifiche necessità nell&#8217;applicativo.</p>



<h3 class="wp-block-heading">Upload dei file</h3>



<p><code>&lt;strong&gt;ServerRequestInterface&lt;/strong&gt;</code> specifica un metodo per recuperare una rappresentazione dei file caricati attraverso una struttura normalizzata in cui ogni elemento è un&#8217;istanza di <code>&lt;strong&gt;UploadedFileInterface&lt;/strong&gt;</code>.</p>



<p><strong><code>$_FILES</code></strong> ha alcuni problemi noti, ad esempio se si tenta di inviare da un form molteplici file attraverso campi di input aventi name &#8220;files&#8221;, l&#8217;array risultante verrà così rappresentato da PHP:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'files' =&gt; array(
        'name' =&gt; array(
            0 =&gt; 'file0.txt',
            1 =&gt; 'file1.html',
        ),
        'type' =&gt; array(
            0 =&gt; 'text/plain',
            1 =&gt; 'text/html',
        ),
        /* etc. */
    ),
)
</pre></div>


<p>Mentre ci si aspetterebbe una rappresentazione di questo tipo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'files' =&gt; array(
        0 =&gt; array(
            'name' =&gt; 'file0.txt',
            'type' =&gt; 'text/plain',
            /* etc. */
        ),
        1 =&gt; array(
            'name' =&gt; 'file1.html',
            'type' =&gt; 'text/html',
            /* etc. */
        ),
    ),
)
</pre></div>


<p>Gli utilizzatori devono conoscere quindi i dettagli dell&#8217;implementazione nel linguaggio PHP e scrivere il codice per interpretare correttamente i dati di un determinato caricamento. </p>



<p>In alcuni casi poi <code>$_FILES</code> non viene popolato con i dati relativi ai file caricati:</p>



<ul><li>Quando il metodo Http non è POST.</li><li>Quando si esegue una unit test.</li><li>Quando si opera in un ambiente non SAPI come ad esempio ReactPHP.</li></ul>



<p>In questi casi si dovranno utilizzare approcci diversi, ad esempio:</p>



<ul><li>Un processo potrebbe analizzare il message body per scoprire i file caricati. </li><li>Negli scenari di unit test, gli sviluppatori devono essere in grado di bloccare e/o simulare i metadati di caricamento del file per convalidare e verificare i diversi scenari.</li></ul>



<p><code>&lt;strong&gt;getUploadedFiles()&lt;/strong&gt;</code> fornisce una struttura normalizzata e l&#8217;implementazione dovrebbe:</p>



<ul><li>Aggregare tutte le informazioni per un determinato caricamento di file e usarle per popolare un&#8217;istanza<code> &lt;strong&gt;Psr\Http\Message\UploadedFileInterface&lt;/strong&gt;</code>.</li><li>Ricreare la struttura ad albero inviata in cui ogni foglia rappresenti un&#8217;istanza di <code>&lt;strong&gt;Psr\Http\Message\UploadedFileInterface&lt;/strong&gt;</code> appropriata.</li><li>La struttura ad albero dovrebbe seguire la struttura dei nomi in cui sono stati inviati i file.</li></ul>



<p>Vediamo un esempio con un singolo campo di input con un &#8220;name semplice&#8221;:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;input type=&quot;file&quot; name=&quot;avatar&quot; /&gt;
</pre></div>


<p>In questo caso, la struttura di $ _FILES sarebbe:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'avatar' =&gt; array(
        'tmp_name' =&gt; 'phpUxcOty',
        'name' =&gt; 'my-avatar.png',
        'size' =&gt; 90996,
        'type' =&gt; 'image/png',
        'error' =&gt; 0,
    ),
)
</pre></div>


<p>Mentre la forma normalizzata restituita da <code>getUploadedFiles()</code> potrebbe essere:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'avatar' =&gt; /* UploadedFileInterface instance */
)
</pre></div>


<p>Vediamo invece un caso di campo di input che utilizza crea un array nell&#8217;attributo nome:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatar]&quot; /&gt;
</pre></div>


<p>In questo caso il contenuto di $_FILES sarà</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array (
    'my-form' =&gt; array (
        'name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'my-avatar.png',
            ),
        ),
        'type' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'image/png',
            ),
        ),
        'tmp_name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 'phpmFLrzD',
            ),
        ),
        'error' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 0,
            ),
        ),
        'size' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; 90996,
            ),
        ),
    ),
)
</pre></div>


<p>E l&#8217;albero corrispondente restituito da <code>getUploadedFiles()</code> dovrebbe essere:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'my-form' =&gt; array(
        'details' =&gt; array(
            'avatar' =&gt; /* UploadedFileInterface instance */
        ),
    ),
)
</pre></div>


<p>Vediamo ora il caso di un array di file:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; gutter: false; title: ; notranslate">
Upload an avatar: &lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatars]&#x5B;]&quot; /&gt;
Upload an avatar: &lt;input type=&quot;file&quot; name=&quot;my-form&#x5B;details]&#x5B;avatars]&#x5B;]&quot; /&gt;
</pre></div>


<p>Ecco cosa conterrà <code>$_FILES</code>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array (
    'my-form' =&gt; array (
        'name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'my-avatar.png',
                    1 =&gt; 'my-avatar2.png',
                    2 =&gt; 'my-avatar3.png',
                ),
            ),
        ),
        'type' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'image/png',
                    1 =&gt; 'image/png',
                    2 =&gt; 'image/png',
                ),
            ),
        ),
        'tmp_name' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 'phpmFLrzD',
                    1 =&gt; 'phpV2pBil',
                    2 =&gt; 'php8RUG8v',
                ),
            ),
        ),
        'error' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 0,
                    1 =&gt; 0,
                    2 =&gt; 0,
                ),
            ),
        ),
        'size' =&gt; array (
            'details' =&gt; array (
                'avatar' =&gt; array (
                    0 =&gt; 90996,
                    1 =&gt; 90996,
                    3 =&gt; 90996,
                ),
            ),
        ),
    ),
)
</pre></div>


<p>L&#8217;array sopra riportato corrisponderebbe alla seguente struttura restituita da <code>&lt;strong&gt;getUploadedFiles()&lt;/strong&gt;</code>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
array(
    'my-form' =&gt; array(
        'details' =&gt; array(
            'avatars' =&gt; array(
                0 =&gt; /* UploadedFileInterface instance */,
                1 =&gt; /* UploadedFileInterface instance */,
                2 =&gt; /* UploadedFileInterface instance */,
            ),
        ),
    ),
)
</pre></div>


<p>Per accedere all&#8217;elemento [1]:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$request-&gt;getUploadedFiles()&#x5B;'my-form']&#x5B;'details']&#x5B;'avatars']&#x5B;1];
</pre></div>


<p>Seguendo il nostro esempio avremo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
$file0 = $request-&gt;getUploadedFiles()&#x5B;'files']&#x5B;0];
$file1 = $request-&gt;getUploadedFiles()&#x5B;'files']&#x5B;1];

printf(
    &quot;Received the files %s and %s&quot;,
    $file0-&gt;getClientFilename(),
    $file1-&gt;getClientFilename()
);
</pre></div>


<p>Poiché le inforazioni sui file caricati, oltre che da <code>$_FILES</code>, possono derivare da altri elementi della richiesta,  è presente il metodo <code>&lt;strong&gt;withUploadedFiles()&lt;/strong&gt;</code> che consente di delegare la normalizzazione ad un altro processo.</p>



<p>Lo standard PSR-7 considera anche le implementazioni in ambienti non SAPI. Pertanto, <code>UploadedFileInterface</code> fornisce metodi per garantire che le operazioni funzionino indipendentemente dall&#8217;ambiente. In particolare:</p>



<ul><li><strong><code>moveTo($targetPath)</code></strong> viene fornito come alternativa sicura e consigliata per richiamare <code>move_uploaded_file()</code> sul file di caricamento temporaneo. Le implementazioni rileveranno il corretto funzionamento da utilizzare in base all&#8217;ambiente.</li><li><code>&lt;strong&gt;getStream()&lt;/strong&gt;</code> restituirà un&#8217;istanza <code>StreamInterface</code>. In ambienti non SAPI, una possibilità proposta è quella di eseguire il parsing dei file caricati nello stream <code>php://temp</code>.</li></ul>



<p>Ad esempio:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; gutter: false; title: ; notranslate">
// Move a file to an upload directory
$filename = sprintf(
    '%s.%s',
    create_uuid(),
    pathinfo($file0-&gt;getClientFilename(), PATHINFO_EXTENSION)
);
$file0-&gt;moveTo(DATA_DIR . '/' . $filename);

// Stream a file to Amazon S3.
// Assume $s3wrapper is a PHP stream that will write to S3, and that
// Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP
// StreamWrapper.
$stream = new Psr7StreamWrapper($file1-&gt;getStream());
stream_copy_to_stream($stream, $s3wrapper);
</pre></div>


<h2 class="wp-block-heading">PSR-7: Interfacce</h2>



<h3><a name="MessageInterface"></a>Psr\Http\Message\MessageInterface</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
interface MessageInterface {
    /**
     * Recupera la versione del protocollo HTTP (Es: &quot;1.1&quot;, &quot;1.0&quot;)
     *
     * @return string HTTP protocol version.
     */
    public function getProtocolVersion();

    /**
     * Restituisce un'istanza con una specifica versione del protocollo HTTP
     *
     * @param string $version HTTP protocol version
     * @return static
     */
    public function withProtocolVersion($version);

    /**
     * Recupera tutti i valori di intestazione del messaggio
     *
     * @return string&#x5B;]&#x5B;] Returns an associative array of the message's headers.
     */
    public function getHeaders();

    /**
     * Verifica se esiste un'intestazione in base al nome senza distinzione tra maiuscole e minuscole.
     *
     * @param string $name Case-insensitive header field name.
     * @return bool
     */
    public function hasHeader($name);

    /**
     * Recupera un valore di intestazione del messaggio in base al nome senza distinzione tra maiuscole e minuscole.
     *
     * @param string $name Case-insensitive header field name.
     * @return string&#x5B;] An array of string values as provided for the given header.
     */
    public function getHeader($name);

    /**
     * Recupera una stringa separata da virgole dei valori per una singola intestazione.
     *
     * @param string $name Case-insensitive header field name.
     * @return string A string of values as provided for the given header concatenated together using a comma.
     */
    public function getHeaderLine($name);

    /**
     * Restituisce un'istanza sostituendo il valore dell'intestazione specificata.
     *
     * @param string $name Case-insensitive header field name.
     * @param string|string&#x5B;] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withHeader($name, $value);

    /**
     * Restituisce un'istanza appendendo un valore al campo di intestazione specificato.
     *
     * @param string $name Case-insensitive header field name to add.
     * @param string|string&#x5B;] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withAddedHeader($name, $value);

    /**
     * Restituisce un'istanza eliminando l'intestazione specificata.
     *
     * @param string $name Case-insensitive header field name to remove.
     * @return static
     */
    public function withoutHeader($name);

    /**
     * Ottiene il corpo del messaggio.
     *
     * @return StreamInterface Returns the body as a stream.
     */
    public function getBody();

    /**
     * Restituisce un'istanza con il corpo del messaggio specificato.
     *   
     * @param StreamInterface $body Body.
     * @return static
     * @throws \InvalidArgumentException When the body is not valid.
     */
    public function withBody(StreamInterface $body);
}
</pre></div>


<p></p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/">PSR-7 Http Message: standard php per Request e Response.</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cesarebordi.it/psr-7-http-message-standard-php-request-response/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PSR-3 Logger Interface: standard log per PHP</title>
		<link>https://www.cesarebordi.it/psr-3-logger-interface-standard-log-php/</link>
					<comments>https://www.cesarebordi.it/psr-3-logger-interface-standard-log-php/#comments</comments>
		
		<dc:creator><![CDATA[cesarebordi]]></dc:creator>
		<pubDate>Wed, 17 Jun 2020 15:21:23 +0000</pubDate>
				<category><![CDATA[Articoli]]></category>
		<category><![CDATA[Lezioni]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programmazione]]></category>
		<category><![CDATA[best practice]]></category>
		<category><![CDATA[guida]]></category>
		<category><![CDATA[lezione]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[logger]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[programmazione ad oggetti]]></category>
		<category><![CDATA[psr]]></category>
		<category><![CDATA[psr-3]]></category>
		<category><![CDATA[psr3]]></category>
		<category><![CDATA[standard]]></category>
		<guid isPermaLink="false">https://www.cesarebordi.it/?p=1154</guid>

					<description><![CDATA[<p>Il PSR-3 Logger Interface del PHP-FIG si propone come uno standard comune per il log degli applicativi in PHP.</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-3-logger-interface-standard-log-php/">PSR-3 Logger Interface: standard log per PHP</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>PSR-3 Logger Interface</strong> del <strong>PHP-FIG</strong> (PHP Framework Interop Group) si propone come uno standard comune per il log degli applicativi in PHP.</p>



<blockquote class="wp-block-quote"><p>The main goal is to allow libraries to receive a <em>Psr\Log\LoggerInterface </em>object and write logs to it in a simple and universal way.</p></blockquote>



<p>L&#8217;obiettivo è quello di far sì che le varie componenti software possano utilizzare un oggetto di tipo <strong><em>Psr\Log\LoggerInterface</em></strong> per scrivere messaggi di log in modo semplice ed universale.</p>



<p>Anche gli applicativi più complessi come i framework <strong>POTREBBERO</strong> <strong>estendere l&#8217;interfaccia del logger per arricchirla</strong> di funzioni, ma <strong>DOVREBBERO</strong> assicurarsi di mantenerne la compatibilità. In questo modo tutti i componenti e le librerie utilizzate potrebbero <strong>scrivere nei log</strong> centralizzati dell&#8217;applicativo. </p>



<p>La parola <strong>implementatore</strong> (<code>&lt;strong&gt;implementor&lt;/strong&gt;</code>) utilizzata nel testo dello <strong>standard PSR3</strong> rappresenta qualcuno che implementa la <code>&lt;strong&gt;&lt;em&gt;LoggerInterface&lt;/em&gt;&lt;/strong&gt;</code> per inserire un logger in una libreria o framework . <br />Gli utenti dei logger vengono definiti utenti (<code>user)</code>.</p>



<p>Per il significato delle altre parole chiave si rimanda alle <a href="https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/#note" target="_blank" rel="noreferrer noopener">note dell&#8217;articolo sul PSR-1</a>.</p>



<h2 class="wp-block-heading">PSR-3: specifiche</h2>



<h3 class="wp-block-heading">LoggerInterface: l&#8217;Interfaccia di base</h3>



<p>La <code>&lt;strong&gt;&lt;em&gt;LoggerInterface&lt;/em&gt;&lt;/strong&gt;</code> <strong>espone otto metodi per scrivere i log</strong> utilizzando i rispettivi livelli dello standard<a href="http://tools.ietf.org/html/rfc5424"> RFC 5424</a>: debug, info, notice, warning, error, critical, alert, emergency. Tali livelli vengono definiti come costanti.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

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';
}

</pre></div>


<p>Un <strong>nono metodo</strong> <em><code>&lt;strong&gt;log&lt;/strong&gt;</code> </em><strong>accetta come primo argomento il livello di log</strong>. <br />La chiamata a questo metodo con una delle costanti di livello <strong>DEVE</strong> avere lo stesso effetto della chiamata al metodo specifico del relativo livello. Chiamare questo metodo con un livello non definito <strong>DEVE</strong> lanciare un&#8217;eccezione di tipo <code>&lt;em&gt;Psr\Log\InvalidArgumentException&lt;/em&gt;</code> se l&#8217;implementazione non prevede tale livello. Gli utenti <strong>NON DOVREBBERO</strong> utilizzare un livello personalizzato senza essere certi che l&#8217;attuale implementazione lo supporti.</p>



<h3 class="wp-block-heading" id="LoggerInterface">Psr\Log\LoggerInterface: il codice</h3>



<p>Di seguito il codice dell&#8217;interfaccia <a href="#LoggerInterface"><code>&lt;strong&gt;&lt;em&gt;LoggerInterface&lt;/em&gt;&lt;/strong&gt;</code></a>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

namespace Psr\Log;

interface LoggerInterface
{
    /**
     * Il sistema è inutilizzabile
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function emergency( $message, array $context = &#x5B;] );

    /**
     * È necessario agire immediatamente.
     *
     * Esempio: Il sito web è down, database non disponibile, ... 
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function alert( $message, array $context = &#x5B;] );

    /**
     * Condizione critica
     *
     * Esepio: Componente non trovato, eccezione inaspettata, ...
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function critical( $message, array $context = &#x5B;] );

    /**
     * Errori di runtime che non richiedono un'azione immediata 
     * ma in genere dovrebbero essere loggati e monitorati.
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function error( $message, array $context = &#x5B;] );

    /**
     * Occorrenze eccezionali che non sono errori
     * Esempio: uso di api deprecate.
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function warning( $message, array $context = &#x5B;] );

    /**
     * Eventi normali ma significativi.
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function notice( $message, array $context = &#x5B;] );

    /**
     * Eventi interessanti
     * Esempio: Log-in utente, esecuzione query, ...
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function info( $message, array $context = &#x5B;] );

    /**
     * Informazioni dettagliate sul debug.
     *
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     */
    public function debug( $message, array $context = &#x5B;] );

    /**
     * Creazione del Log con un livello arbitrario.
     *
     * @param mixed   $level
     * @param string  $message
     * @param mixed&#x5B;] $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log( $level, $message, array $context = &#x5B;] );
}
</pre></div>


<p>La gestione dell&#8217;eccezione di <code>&lt;em&gt;Psr\Log\InvalidArgumentException&lt;/em&gt;</code> estende la classe nativa di php <code>&lt;a rel=&quot;noreferrer noopener&quot; href=&quot;https://www.php.net/manual/en/class.invalidargumentexception.php&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;InvalidArgumentException&lt;/em&gt;&lt;/a&gt;</code> e deve essere lanciata dal logger qualora vengano passati ai metodi dei paramentri non corretti.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

namespace Psr\Log;

class InvalidArgumentException extends \InvalidArgumentException {
    // class body
}
</pre></div>


<h3 class="wp-block-heading">PSR-3: messaggi</h3>



<p><strong>Ogni metodo accetta una stringa come messaggio</strong> o un oggetto con un metodo __toString (). Gli implementatori <strong>POSSONO implementare una gestione personalizzata per gli oggetti passati al metodo</strong>. In caso contrario, gli implementatori <strong>DEVONO eseguire il type casting del valore passato in stringa</strong>.</p>



<p>Il messaggio <strong>PUÒ contenere un placeholder</strong> che gli implementatori possono sostituire con i valori presi dall&#8217;array del parametro context.</p>



<p>I nomi dei <strong>placeholder DEVONO corrispondere alle chiavi del context array</strong>.</p>



<p>I nomi dei <strong>placeholder DEVONO essere delimitati fra due parentesi graffe singole</strong> <code>{placeholder}</code>. <strong>NON DEVE esserci spazio tra i delimitatori e il nome placeholder</strong>.<br /><br />I nomi dei <strong>placeholder DOVREBBERO essere composti solo dai caratteri <code>A-Z</code>, <code>a-z</code>, <code>0-9</code>, underscore <code>_</code>, e punto <code>.</code></strong>. L&#8217;uso di altri caratteri è riservato per future modifiche delle specifiche dei placeholder.<br /><br />Gli implementatori POSSONO usare i placeholder per implementare <em>escaping strategy</em> o gestire la traduzione dei messagi. Gli utenti non DOVREBBERO effettuare l&#8217;escape preventivo dei placeholder poiché non possono sapere in quale contesto i dati inseriti nei messaggi verranno visualizzati.<br /><br />Il PHP-FIG fornisce una semplice funzione di esempio per comprendere meglio la funzione dei placeholder nei messaggi di log.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

/**
 * Sostituisce i placeholder dei messaggi con i rispettivi valori.
 */
function interpolate($message, array $context = &#x5B;]) {
    // Crea l'array delle sostituzioni
    $replace = array();
    foreach ($context as $key =&gt; $val) {
        // controlla che il valore possa essere usato come stringa.
        if (!is_array($val) &amp;&amp; (!is_object($val) || method_exists($val, '__toString'))) {
            $replace&#x5B;'{' . $key . '}'] = $val;
        }
    }

    // Sostituisce i placeholder con i rispettivi valori.
    return strtr($message, $replace);
}

// Messaggio contenente il placeholder fra graffe
$message = &quot;User {username} created&quot;;

// Il context array con i dati da sostituire ai placeholder
$context = array('username' =&gt; 'bolivar');

// stampa &quot;User bolivar created&quot;
echo interpolate($message, $context);
</pre></div>


<h3 class="wp-block-heading">Context data</h3>



<p>Ogni <strong>metodo accetta un array contenente dati contestuali (context data) per gestire ulteriori informazioni che non possano essere ridotte alla stringa del messagio</strong>. L&#8217;array può contenere qualsiasi tipo di dato. Gli implementatori <strong>DEVONO  utilizzare i dati di contesto con moderazione</strong>. Un context data <strong>NON DEVE generare un&#8217;eccezione né errori php</strong> di tipo error, warning o notice</p>



<p>Se nei context data viene passato <strong>un oggetto di tipo <code>&lt;em&gt;Exception&lt;/em&gt;</code>, questo DEVE essere passato nella chiave <code>&#039;exception&#039;</code></strong>. Poiché il log delle eccezioni è un&#8217;esigenza diffusa, questa regola dello standard PSR-3 consente di registrare questo tipo di evento ed il relativo stack trace. Gli implementatori DEVONO verificare che il dato contenuto nella chiave <strong><code>&#039;exception&#039;</code></strong> sia realmente <strong>un oggetto di tipo <code>Exception</code></strong> dato che l&#8217;elemento dell&#8217;array potebbe contenere qualsiasi tipo di dato.</p>



<h2 class="wp-block-heading">PSR-3: classi helper ed interfacce</h2>



<p>La classe di esempio <code>&lt;em&gt;Psr\Log\AbstractLogger&lt;/em&gt;</code> facilita l&#8217;implementazione di <code>&lt;em&gt;LoggerInterface&lt;/em&gt;</code> estendendola e implementando il metodo <code>log</code> generico. Gli altri otto metodi richiamano il metodo <code>&lt;em&gt;log&lt;/em&gt;</code> passandogli la corretta costante di livello, messaggio ed eventuale contesto.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

namespace Psr\Log;

abstract class AbstractLogger implements LoggerInterface {

    public function emergency($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::EMERGENCY, $message, $context);
    }

    public function alert($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::ALERT, $message, $context);
    }

    public function critical($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::CRITICAL, $message, $context);
    }

    public function error($message, array $context = &#x5B;])) {
        $this-&gt;log(LogLevel::ERROR, $message, $context);
    }

    public function warning($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::WARNING, $message, $context);
    }

    public function notice($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::NOTICE, $message, $context);
    }

    public function info($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::INFO, $message, $context);
    }

    public function debug($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::DEBUG, $message, $context);
    }
}
</pre></div>


<p>Similmente ad <code>AbstractLogger</code> è possibile creare un trait <code>&lt;em&gt;Psr\Log\LoggerTrait&lt;/em&gt;</code> utile nel caso si voglia implementare il logger in diverse classi. Poiché i traits non possono implementare delle interfacce, in questo caso si dovrà di fatto riscrivere il codice di <em>LoggerInterface</em>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
namespace Psr\Log;

trait LoggerTrait {

    public function emergency($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::EMERGENCY, $message, $context);
    }

    public function alert($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::ALERT, $message, $context);
    }

    public function critical($message, array $context = array&#x5B;]) {
        $this-&gt;log(LogLevel::CRITICAL, $message, $context);
    }

    public function error($message, array $context = &#x5B;])) {
        $this-&gt;log(LogLevel::ERROR, $message, $context);
    }

    public function warning($message, array $context = &#x5B;]) {
        $this-&gt;log(LogLevel::WARNING, $message, $context);
    }

    public function notice($message, array $context = &#x5B;])
    {
        $this-&gt;log(LogLevel::NOTICE, $message, $context);
    }

    public function info($message, array $context = &#x5B;])
    {
        $this-&gt;log(LogLevel::INFO, $message, $context);
    }

    public function debug($message, array $context = &#x5B;])
    {
        $this-&gt;log(LogLevel::DEBUG, $message, $context);
    }

    abstract public function log($level, $message, array $context = &#x5B;]);
}
</pre></div>


<p>Veniamo ora al &#8220;piuttosto che niente&#8221;! <code>&lt;em&gt;Psr\Log\NullLogger&lt;/em&gt;</code> implementa  <code>&lt;em&gt;AbstractLogger&lt;/em&gt;</code> e <strong>PUÒ</strong> essere usato dagli utenti, se non gli viene fornito un apposito log, da utilizzare con una fall-back. E&#8217; una sorta di &#8220;black hole&#8221; in cui inviare qualcosa che potrà essere loggato.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&lt;?php

namespace Psr\Log;

class NullLogger extends AbstractLogger
{
    /**
     * Logs with an arbitrary level.
     *
     * @param mixed  $level
     * @param string $message
     * @param array  $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, $message, array $context = array())
    {
        // class body
    }
}
</pre></div>


<p><code>&lt;em&gt;Psr\Log\LoggerAwareInterface&lt;/em&gt;</code> contiene solo un metodo <code>setLogger(LoggerInterface $logger)</code> che <strong>PUÒ</strong> essere utilizzato dai framework per collegarsi automaticamente a istanze del logger.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&lt;?php

namespace Psr\Log;

interface LoggerAwareInterface {
    public function setLogger(LoggerInterface $logger);
}
</pre></div>


<p>Il trait <code>Psr\Log\LoggerAwareTrait</code> <strong>PUÒ</strong> essere utilizzato per implementare facilmente la medesima interfaccia in qualsiasi classe così da avere accesso all&#8217;oggetto <code>$this-&gt;logger</code>.</p>



<h2 class="wp-block-heading">PSR-3 Logger package</h2>



<p>Le interfacce e le classi descritte, nonché le relative classi di eccezione e una suite di test per verificare l&#8217;implementazione sono fornite come parte del pacchetto <a href="https://packagist.org/packages/psr/log" target="_blank" rel="noreferrer noopener">psr/log</a> sul sito ufficiale di PHP-FIG</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-3-logger-interface-standard-log-php/">PSR-3 Logger Interface: standard log per PHP</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cesarebordi.it/psr-3-logger-interface-standard-log-php/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>PSR-1: regole per la scrittura di codice PHP</title>
		<link>https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/</link>
					<comments>https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/#respond</comments>
		
		<dc:creator><![CDATA[cesarebordi]]></dc:creator>
		<pubDate>Mon, 15 Jun 2020 10:08:11 +0000</pubDate>
				<category><![CDATA[Articoli]]></category>
		<category><![CDATA[Lezioni]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programmazione]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[guida]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fig]]></category>
		<category><![CDATA[phpfig]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[programmazione ad oggetti]]></category>
		<category><![CDATA[psr]]></category>
		<category><![CDATA[psr-1]]></category>
		<category><![CDATA[psr1]]></category>
		<category><![CDATA[standard]]></category>
		<guid isPermaLink="false">https://www.cesarebordi.it/?p=1170</guid>

					<description><![CDATA[<p>PSR-1 è lo standard promosso da PHP-FIG per definire delle regole per la scrittura di codice PHP così da facilitarne la lettura e la comprensione.</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/">PSR-1: regole per la scrittura di codice PHP</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>PSR-1</strong> è lo standard promosso da <strong><a rel="noreferrer noopener" href="https://www.php-fig.org/" target="_blank">PHP-FIG</a></strong> (<strong>PHP Framework Interop Group</strong>) che vuole definire le <strong>regole per la scrittura di codice PHP</strong> così da <strong>facilitare la lettura e la comprensione del codice</strong> da parte della community degli sviluppatori.</p>



<p>Prima di procedere con la lettura della lezione sullo <strong>standard PSR1</strong> consiglio di leggere le <a href="#note">note</a> in fondo alla pagina. Inoltre, nella sezione &#8220;<a href="https://www.cesarebordi.it/category/articoli/lezioni/">Lezioni</a>&#8220;, è possibile trovare altro materiale sugli standard <strong>PHPFIG</strong>.</p>



<h2 class="wp-block-heading">PSR-1: in breve</h2>



<ul><li>I <strong>file PHP DEVONO usare solo i tag <code>&lt;?php</code> e <code>&lt;?=</code></strong>,</li><li><strong>DEVONO usare solo la codifica UTF-8</strong> priva di BOM,</li><li><strong>DOVREBBERO dichiarare classi, funzioni, costanti</strong>, &#8230;<strong> OPPURE DOVREBBERO eseguire altri tipi di azioni logiche</strong> come generare output, modificare parametri di configurazione del php.ini, includere file &#8230; ma NON DOVREBBERO fare entrambe le cose.</li><li>I <strong>Namespaces e i Class Names DEVONO seguire lo standard per “autoloading” PSR-4</strong>: una sola classe in un solo file, namespace di almeno un livello indicante il vendor-name.</li><li>I <strong>Class Names DEVONO essere dichiarati in <code>StudlyCaps</code></strong>.</li><li>Le <strong>costanti DEVONO essere dischiarate in maiuscolo utilizzando l&#8217;underscore come separatore</strong>.</li><li>I <strong>nomi dei metodi DEVONO essere dichiarati in <code>camelCase</code></strong>.</li></ul>



<h2 class="wp-block-heading">PSR-1: files</h2>



<h3 class="wp-block-heading">PHP Tags</h3>



<p>Il codice PHP deve essere dichiarato attraverso i tag <code>&lt;?php ?&gt;</code> oppure gli short-echo <code>&lt;?= ?&gt;</code> tags. NON DEVE utilizzare altre varianti di tag dichiarativi (es: <code>&lt;? ?&gt;</code>).</p>



<h3 class="wp-block-heading">Codifica dei caratteri</h3>



<p>Il file <strong>PHP DEVE utilizzare solo la codifica UTF-8</strong> ed essere privo di <a href="https://it.wikipedia.org/wiki/Byte_Order_Mark" target="_blank" rel="noreferrer noopener">BOM</a>.</p>



<h3 class="wp-block-heading">Dichiarazioni ed effetti collaterali (side effects)</h3>



<p>Un file <strong>DOVREBBE dichiarare nuovi &#8220;simboli&#8221;</strong> (classi, funzioni, costanti, &#8230;) senza causare altri &#8220;effetti collaterali&#8221;<strong> OPPURE DOVREBBE eseguire una logica con effetti collaterali</strong>, <strong>MA NON DOVREBBE fare entrambe le cose</strong>.</p>



<p>Lo standard spiega che l&#8217;espressione &#8220;<strong>effetti collaterali</strong>&#8221; (side effects) indica l&#8217;esecuzione di una logica non direttamente correlata alla dichiarazione di classi, funzioni, costanti, ecc, ma correlata direttamente all&#8217;inclusione del file stesso. </p>



<p>Vengono poi fatti alcuni esempi di &#8220;effetti collaterali&#8221; a titolo esemplificativo: generazione di output, uso esplicito di <code>require</code> o <code>include</code>, connessione a servizi esterni, modifica di parametri del php.ini, generazione di errori o eccezioni, modifica di variabili statiche o globali, lettura/scrittura di file, &#8230;</p>



<p>Ecco un esempio di file non conforme allo standard con la coopresenza di dichiarazioni ed &#8220;effetti collaterali&#8221;.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
// effetto collaterale: cambio ini setting
ini_set('error_reporting', E_ALL);

// effetto collaterale: carico un file
include &quot;file.php&quot;;

// effetto collaterale: genero output
echo &quot;&lt;html&gt;\n&quot;;

// dichiarazione una funzione
function foo() {
    // function body
}
</pre></div>


<p>Il seguente esempio mostra un file conforme allo standard contenete solo delle dichiarazioni:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
// dichiarazione una funzione
function foo() {
    // function body
}

// la dichiarazione condizionale non è un effetto collaterale.
if (! function_exists('bar')) {
    function bar() {
        // function body
    }
}

</pre></div>


<h2 class="wp-block-heading">PSR-1: namespace e class names</h2>



<p>I <strong>namespaces</strong> ed i <strong>class names</strong> <strong>DEVONO essere conformi ad allo standard per l&#8217;autoloading</strong> <a rel="noreferrer noopener" href="https://www.php-fig.org/psr/psr-4/" target="_blank">PSR-4</a>.</p>



<p>Ciò significa che <strong>ogni classe DEVE essere dichiarata in un file dedicato</strong> e <strong>DEVE trovarsi in un Namespace di almeno un livello indicante il vendor-name</strong>, in pratica l&#8217;indicazione dello sviluppatore.</p>



<p>I <strong>class names DEVONO essere dichiarati in <code>StudlyCaps</code></strong>.</p>



<p>ll codice scritto da PHP 5.3 in avanti <strong>DEVE utilizzare namespaces formali</strong>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
// PHP 5.3 e successivi:
namespace Vendor\Model;

class Foo {
  // Class body
}
</pre></div>


<p>Il codice scritto per PHP 5.2 e versioni precedenti DOVREBBE usare la convenzione pseudo-namespacing con prefissi Vendor_ nei nomi delle classi.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
// PHP 5.2.x e versioni precedenti:
class Vendor_Model_Foo {
  // Class body
}

</pre></div>


<h2 class="wp-block-heading">PSR-1: costanti di classe, proprietà e metodi</h2>



<p>Il termine “class” si usa qui in senso più ampio per riferirsi a tutte le classi, le interfacce ed i traits.</p>



<h3 class="wp-block-heading">Costanti</h3>



<p>Le <strong>costanti di classe DEVONO essere dischiarate in maiuscolo utilizzando l&#8217;underscore come separatore</strong>. Personalmente applico questa regola a tutte le costanti comprese quelle definite con define().</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
namespace Vendor\Model;

class Foo {
    const VERSION = '1.0';
    const DATE_APPROVED = '2012-06-01';
}
</pre></div>


<h3 class="wp-block-heading">Proprietà</h3>



<p>Lo standard evita intenzionalmente di fornire consigli riguardanti l&#8217;uso dei nomi di prorpietà <code>$StudlyCaps</code>, <code>$camelCase</code>, or <code>$under_score</code> property names.</p>



<p>Qualunque sia la convenzione di denominazione utilizzata DOVREBBE essere applicato in modo coerente.</p>



<h3 class="wp-block-heading">Metodi</h3>



<p>I nomi dei <strong>metodi DEVONO essere dichiarati in <code>camelCase()</code></strong>.</p>



<hr class="wp-block-separator"/>



<h2 class="wp-block-heading">PSR1 nel lavoro di tutti i giorni</h2>



<p>Il nuovo <strong>framework CoreBox</strong> che stiamo sviluppando alla <a rel="noreferrer noopener" href="https://www.communicationbox.it" target="_blank">Communication Box </a>adererisce perfettamente allo <strong>standard PSR1</strong>. Questo facilita notevolmente lo sviluppo poiché ogni componente del team trova sempre una certa familiarità nel leggere il codice scritto dai colleghi.</p>



<hr class="wp-block-separator"/>



<h4 class="wp-block-heading" id="note"><strong>Note</strong></h4>



<p>Quando si legge un documento del PHP-FIG le parole DEVE (<strong><code>MUST</code></strong>), NON DEVE (<strong><code>MUST NOT</code></strong>), RICHIESTO (<strong><code>REQUIRED</code></strong>), POTRÀ (<strong><code>SHALL</code></strong>),  NON POTRÀ (<strong><code>SHALL NOT</code></strong>), DOVREBBE (<strong><code>SHOULD</code></strong>),  NON DOVREBBE (<strong><code>SHOULD NOT</code></strong>), RACCOMANDATO (<strong><code>RECCOMANDED</code></strong>), PUÒ (<strong><code>MAY</code></strong>) e OPZIONALE (<strong><code>OPTIONAL</code></strong>) vanno interpretati secondo quanto descritto nel documento <a rel="noreferrer noopener" href="http://www.ietf.org/rfc/rfc2119.txt" target="_blank">RFC 2119</a>.</p>



<p>Lo stile <strong></strong><strong><code>StudlyCaps</code></strong>, noto anche come PascalCase, impone che la prima lettera di ogni parola sia in maiuscolo.<strong> </strong>Una stringa in questo stile<strong> deve iniziare sempre con la lettera maiuscola</strong>.</p>



<p>Lo stile <strong></strong><strong><code>camelCase</code></strong>, proprio come in un cammello, impone che le gobbe siano solo in mezzo. Una stringa in questo stile <strong>deve iniziare sempre con la lettera minuscola</strong>.</p>
<p>L'articolo <a href="https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/">PSR-1: regole per la scrittura di codice PHP</a> sembra essere il primo su <a href="https://www.cesarebordi.it">Cesare Bordi | Innovation Manager &amp; Back-end Developer</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cesarebordi.it/psr-1-regole-scrittura-codice-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
