Olá pessoal, meu nome é Alex. Quero apresentar a minha estrutura PHP para criar microsserviços. Ele surgiu do meu experimento de três anos atrás, que mais tarde se transformou em um projeto para animais de estimação e, posteriormente, nesse contexto, criei vários projetos de produção.
Quando comecei, decidi tomar uma decisão que:
- pode ser facilmente integrado a projetos existentes;
- você pode criar rapidamente pelo menos algo funcionando;
- os desenhos mais concisos e expressivos;
- sabiamente usou os recursos do PHP moderno.
Então, por onde você começa? Claro da fonte! Você pode assisti-los no
githubBem, para não entrar em discussões longas, vamos começar imediatamente com um exemplo de trabalho.
Primeiro, precisamos de .htaccess, no qual configuraremos várias regras:
# use mod_rewrite for pretty URL support RewriteEngine on RewriteRule ^([a-z0-9A-Z_\/\.\-\@%\ :,]+)/?(.*)$ index.php?r=$1&%{QUERY_STRING} [L] RewriteRule ^/?(.*)$ index.php?r=index&%{QUERY_STRING} [L]
Então você pode criar seu primeiro serviço. Nele, criaremos um ponto de extremidade que processará o método GET e retornará uma mensagem de que está tudo bem com ele. Um tipo de verificação de saúde.
Para começar, precisamos conectar nossa estrutura:
require_once ('vendor/service/service.php');
Em seguida, criamos uma classe para microsserviço:
class TodoService extends ServiceBase implements ServiceBaseLogicInterface { }
Aqui temos:
- ServiceBase é uma classe de serviço básica com a funcionalidade mais básica e mais utilitária;
- ServiceBaseLogicInterface é a interface que qualquer classe precisa implementar se desejar fornecer manipuladores de pontos de extremidade. Embora essa interface não imponha nenhum requisito especial à sua classe. Feito apenas para uma digitação mais rigorosa.
Em seguida, obtemos o primeiro manipulador de terminal:
public function action_ping() { return ('I am alive!'); }
Em seguida, lançamos nosso primeiro microsserviço:
Service::start('TodoService');
Juntando tudo, temos:
class TodoService extends ServiceBase implements ServiceBaseLogicInterface { public function action_ping() { return ('I am alive!'); } } Service::start('TodoService');
Uma pergunta razoável pode surgir - e em qual URL essa funcionalidade está disponível? O fato é que, ao definir um método com o prefixo action_ <part-name>, você deixou claro para o serviço que ele é um manipulador de URL <partpartname>, ou seja, no nosso caso, será algo como
localhost / pingO sublinhado no nome do método muda para -. I.e. O método action_hello_world estará disponível em
localhost / hello-worldNós seguimos em frente.
Assim como para aplicativos GUI, seria bom usar o MVC (ou outro padrão com separação do componente visual e da lógica), bem como no microsserviço. Coisas que podem ser esmagadas são melhor destruídas.
I.e. no nosso caso, deixe a classe de serviço continuar executando funções utilitárias para inicializar o serviço e iniciar o manipulador desejado e colocar a lógica em uma classe separada. Para fazer isso, modificamos nosso código da seguinte maneira:
class TodoLogic extends ServiceBaseLogic { public function action_ping() { return ('I am alive!'); } } class TodoService extends ServiceBase { } Service::start('TodoService', 'TodoLogic');
Então nós temos uma classe com lógica:
class TodoLogic extends ServiceBaseLogic
Herdado da classe base ServiceBaseLogic (ela possui um mínimo de funções, portanto, a examinaremos em detalhes posteriormente).
A classe TodoService deixou de implementar a interface ServiceBaseLogicInterface (na verdade, ela não desapareceu, apenas a classe ServiceBaseLogic agora a implementa).
Após remover a lógica, a classe TodoService ficou vazia e pode ser cortada com segurança, reduzindo ainda mais o código:
class TodoLogic extends ServiceBaseLogic { public function action_ping() { return ('I am alive!'); } } Service::start('ServiceBase', 'TodoLogic');
Aqui, a classe ServiceBase é responsável por iniciar o serviço, não o nosso.
Nós dirigimos ainda mais.
No processo de usar minha estrutura, em um determinado momento, começaram a surgir classes com lógica de tamanho monstruoso. O que irritou meu senso de beleza, por um lado, por outro lado, o Sonar ficou indignado, por outro lado, o conceito de dividir métodos em métodos de leitura e escrita (ver CQRS) não estava claro como implementá-lo.
Portanto, em um determinado momento, tornou-se possível agrupar manipuladores de terminais de acordo com um ou outro atributo de acordo com diferentes classes de lógica e, se necessário, executá-los no mesmo serviço ou distribuí-los sem esforço em diferentes.
I.e. Você pode executar toda a lógica CRUD em um serviço. E pode ser dividido em dois serviços:
- um fornece métodos de leitura;
- e o outro fornece métodos de modificação de dados.
Vamos agora adicionar um método de criação de entidade e um método de recuperação de lista de entidades ao nosso exemplo:
class TodoSystemLogic extends ServiceBaseLogic { public function action_ping() { return ('I am alive!'); } } class TodoReadLogic extends ServiceBaseLogic { public function action_list() { return ('List!'); } } class TodoWriteLogic extends ServiceBaseLogic { public function action_create() { return ('Done!'); } } Service::start('ServiceBase', [ 'TodoSystemLogic', 'TodoReadLogic', 'TodoWriteLogic' ]);
Nós tocaremos apenas nas alterações:
- apareceram as classes TodoSystemLogic (métodos do sistema), TodoReadLogic (métodos de leitura), TodoWriteLogic (métodos de gravação);
- ao iniciar o serviço, transferimos não uma classe com lógica, mas várias.
Isso é tudo por hoje. Discutirei outros recursos da estrutura nos seguintes artigos. Existem muitos deles. Enquanto isso, você pode ver por si mesmo o
que é interessante lá .