PHP Avançando com OO - Atualização 1

Aula 02 - Listando registros com PDO
Nesta aula criamos um DB e fizemos a conexão utilizando o PDO.
Não conheço esse método de conexão mas podemos verifcar mais informações em PHP Documentation.
A conexão é feita utilizando o statement.
$conn = new \PDO("mysql:host=localhost;dbname=php_avanc_oo", "root", "");

$query = "SELECT * FROM products";

$stmt = $conn->prepare($query);
$stmt->execute();
$list = $stmt->fetchAll(\PDO::FETCH_ASSOC);

print_r($list);

Aula 03 - Class Product
Agora que criamos a conexão vamos criar uma classe para executar a listagem dos dados no DB. Na classe criamos um atributo privado para a conexão. Esse atributo será definido pela função construtora da classe.
Ainda na classe criamos o método list() que executa a query que haviamos criado na aula anterior. Esse método retorna os dados da query.
Feito isso instanciamos a classe passando a conexão como parametro e executamos o método list() para recebermos o mesmo resultado da query feita anteriormente.
Aula 04 a 05 - Interface e Class Conn / Dependecy injection
Antes de criarmos uma interface ou classe para a conexão passamos para o construtor da classe Products o tipo de parametro esperado (no caso \PDO).
Vamos agora começar o encapsulamento da conexão.
Primeiro criamos uma interface que irá definir quais os métodos necessários para a criação das classes de conexão.
Em seguida criamos a classe de conexão que implementa a interface (ou seja necessita que seja criado o método definido na interface).
Essa classe terá os atributos de conexão que serão recebidos no método construtor.
O método implementado nessa classe irá retornar a conexão em PDO com os dados recebidos no construtor.
Criada essa estrutura devemos incluir os arquivos no arquivo principal e instanciar a classe de conexão.
A classe Product agora receberá no seu construtor não mais um PDO, mas um objeto com a interface criada.
O construtor por sua vez executará não mais a variável conn mas sim o método da conexão recebido.
Quando criamos um sistema com vários objetos começamos a ter o problema de dependecy injection, que é a vinculação de várias classes diferentes na estrutura dos arquivos o que pode tornar a manutenção inviável. A seguir veremos como padronizar os serviços para evitar esse problema.
Aula 06 - Service Container
Um service container é uma classe responsável por executar métodos que instanciam os objetos necessários para a aplicação. Nele criamos através de métodos as instancias com os parametros necessários para execução. Esses métodos são do tipo static para não haver a necessidade de serem instanciados e com visibilidade public.
Essa tarefa pode ser realizada através de frameworks que automatizam a sua criação.
Aula 07 a 08 - Refatorano a aplicação / Instalando o Pimple
Nesse momento vamos fazer a instalação do Composer. Fiz a instalação para Windows baixado do site e no Linux com o apt-get. A diferença é que a versão Linux é a 1.10.1 e a Windows é a 2.3.5
Antes de inicializar o Composer devemos criar um arquivo composer.json com o seguinte conteudo:
{
"autoload": {
"psr-4": {
"Source\\": "src/"
}
}
}

Com isso instalamos o Composer com o comando:
$ composer install
Como fiz a instalação pelo WSL instalei a versão 1.10 e recebi algumas mensagens de erro (deprecated). Vamos ver ser vai funcionar.
Na verdade precisamos inserir '\\' após o Source no arquivo composer.json. Com essa inclusão o Composer foi instalado corretamente. Criamos um diretório /src/Source que revebe os arquivos das classes e o diretório /public que recebe o arquivo principal da aplicação. Esse arquivo passará a ter apenas a inclusão do arquivo autoloader.php (no meu caso inclui o arquivo autoloader_psr4.php pois não tinha no diretório vendor o outro arquivo). Com a instalação correta foi instalado o arquivo autoloader.php
Nos asquivos de classes devemos definir os namespace Source;.
A seguir vamos instalar o Pimple através do repositório GitHub. Segundo o repositório devemos incluir o Pimple no arquivo .json, mas utilizamos o seguinte comando no prompt:
$ composer require pimple/pimple "^3.0"
Com isso temos instalado o Pimple em nosso projeto.
A partir daqui podemos criar nossos containers. A seguir o exemplo utilizado para teste:
use Pimple\Container;

$container = new Container();

$container['date'] = function () {
return new \DateTime();
};

var_dump($container['date']);

Instanciamos a classe Container() e a partir disso podemos criar novas instancias para nossas classes e executá-las a partir do objeto $container com o atributo definido para o objeto que queremos executar. A vantagem desse método é que diferente de instanciar o objeto no projeto ($date = new \DateTime;) que fica instanciado diretamente, só executamos o instanciamento quando chamamos o objeto.
Aula 09 - Serviço compartilhado
Com o Pimple os objetos são instanciados por padrão apenas uma vez e são reaproveitados toda a vez que são chamados. Quando precisamos que o objeto seja reinstanciado cada vez que for chamado podemos utilizar o método factory():
$container['date2'] = $container->factory(function () {
return new \DateTime();
});

Como estamos utilizando o método DateTime() nos dois objetos podemos perceber a difenrença quando executamos os containers com um tempo entre eles. No objeto instanciado no formato padrão o retorno do objeto é o mesmo tempo mesmo com a pausa entre eles. Já utilizando o método factory() temos tempos diferentes a cada nova chamada. Isso porque ele é reinstanciado e recebe um novo valor.
Aula 10 a 13 - Registrando Serviços / Config e Services / Service Product / Interface Product
Vamos agora criar os containers da aplicação. Para isso criamos os containers para a connexão e para a listagem de produtos:
$container['conn'] = function () {
return new \Source\Conn('mysql:host=localhost;dbname=php_avanc_oo', "root", "");
};

$container['product'] = function ($c) {
return new \Source\Product($c['conn']);
};

Note que para chamar outro container utilizamos um parametro qualquer na função e chamamos ele com o nome do parametro do container.
Aqui tivemos um erro pois precisamos passar o namespace completo no arquivo do autoload do composer.json. Após corrigir o arquivo .json devemos recarregar o Composer com o comando:
$ composer update
Vamos separar agora os serviços e as configurações em arquivos separados. Primeiro criamos um arquivo service com os containers de conexão e de produtos. Em seguida criamos um arquivo config que passará a instanciar os containers e armazenar as variáveis de conexão (também em containers).
Para seguir com as abstrações criamos uma interface e uma class para o ServiceProducts, ou seja, criamos a inteface com os métodos necessários e a classe implementando o método de listagem e os futuros métodos de save, update e delete. Com isso a classe Product passa a receber apenas os atributos (os campos do DB). Criamos nessa classe os métodos getters/setters.
Criamos uma interface para a classe Product para enviar os dados para a classe ServiceProduct (pelo que pude entender enviamos as interfaces para não ter que enviar a classe inteira).
No arquivo de service passamos a fazer a conexão com o DB a partir do container serviceProduct e não mais pelo container product (esse container só será utilizado para as opções de set e get nos atributos que não serão implementadas).
As variáveis $product utilizadas no service não são necessárias para a listagem de dados.