PHP DO BÁSICO AO AVANÇADO – AULA 20 – Extensões da linguagem e Funções da APCu Cache

Tempo de Leitura: 18 Minutos

O PHP é uma linguagem que suporta o uso de algumas extensões, como já foi mostrado anteriormente, que adicionam ou alteram alguns comportamentos padrão da linguagem, diferentes dos objetos criados, essas extensões podem ser implementadas em outras linguagens de programação, como C/C++ ou qualquer outra, a maioria delas é distribuida pelo PECL que é um repositório para extensões PHP, fornecendo um diretório de todas as extensões conhecidas e facilidades de hospedagem para download e desenvolvimento de novas extensões para o PHP, outro sistema que também é usado é o PEAR, que é a abreviação de ” PHP Extension and Application Repository “, e seu é fornecer uma biblioteca estruturada de código aberto para usuários de PHP, um sistema para distribuição de código e manutenção de pacotes, um estilo padrão para código escrito em PHP e um site e listas de discussão e espelhos de download para apoiar a comunidade PHP / PEAR. Nesta aula vamos falar especificamente desses 2 assuntos e abordar algumas de suas extensões que modificam o comportamento padrão, vamos a elas.

PEAR x PECL

PEAR é particionado em ” pacotes “, onde cada pacote é um projeto separado com sua própria equipe de desenvolvimento, número de versão, ciclo de lançamento, documentação e uma relação definida com outros pacotes incluindo dependências. Os pacotes são distribuídos como arquivos tar compactados com um arquivo de descrição dentro e instalados em seu sistema local usando o instalador PEAR, e podem se relacionar entre si por meio de dependências explícitas, mas não há um relacionamento de dependência automático entre os pacotes com base no nome do pacote.

O PEAR já vem junto com o PHP desde a versão 5.3, então se você usa uma versão mais recente (recomendamos o uso sempre da ultima versão estável) então, não há necessidade de instalar nada, caso queira saber se ele está instalado e habilitado de maneira global, basta digitar em uma janela de terminal ou prompt de comando pear help e você vai ver a lista de opções.

PECL (pronuncia-se “pickle”) é um projeto separado que distribui extensões PHP com código compilado escrito em C, como a extensão PDO, as extensões PECL também são distribuídas como pacotes e podem ser instaladas usando o instalador PEAR, ou, se você usa windows, pode baixar as bibliotecas DLL das extensões já em formato binário e prontas para uso.

Extensões PECL

Para instalar as extensões PECL você pode utilizar o comando pecl install extensio-name.ver.x e estando todas as dependências satisfeitas o próprio sistema faz a instalação e a habilitação da extensão, que pode ser feita diretamente no php.ini ou atraves da função dl() do php, se esta estiver habilitada para carregar a extensão dinamicamente.

Atualmente centenas de extensões estão disponíveis, e com os mais diversos propósitos, autenticação, cache, avaliação e comparação, configuração do ambiente e proteção, uso através do console, extensões de acesso a bancos de dados, data e hora, criptografia, manipulação de outros formatos de arquivo, controle de eventos do so, manipulação do sistema de arquivos, interface gráfica e ambiente, tratamento de html e parses em geral, manipulação de protocolo direto e extensões de protocolos suportados, internacionalização, manipulação gráfica de imagens, suporte a multiplos idiomas, funções matemáticas, manipulação de email, manipulação de arquivos e do sistema de audio, funções de acesso a camadas de rede, criptografia de moedas e sistemas financeiros, motor de pesquisa e manipulação de texto, segurança, controle de stream (audio e video), controle de versionamento, virtualização, coleta de lixo e manipulação de memória, SOAP e XML, entre outras.

Extensões PEAR

Por outro lado, extensões da PEAR são escritas em PHP e você pode utiliza-las em seus projetos, essas extensões ou bibliotecas são instaladas de maneira global, ou seja, todas podem ser usadas por todos os projetos existentes no servidor.

Desde o lançamento do PHP7 o PEAR vem caindo em desuso, pois necessita de um repositório global dos componentes, um gerenciador de dependências que vem se tornando cada vez mais utilizado, é o COMPOSER, devido a forma mais simplista para os mantenedores dos pacotes, muito similar ao npm do node.js, ou ousaria até a compara-lo com o apt-get da debian, vamos falar um pouco mais sobre ele.

Grande parte do código em PEAR está desatualizado, pois o desenvolvedor precisa fazer com que os pacotes sejam revisados ​​pela equipe da PEAR antes de ser publicado o que limita o número de pacotes disponíveis, além disso, ele segue convenções de nomenclatura não amplamente utilizadas pelos desenvolvedores PHP. Bem, há a falta de gerenciamento de dependências no PEAR, que francamente deve ser a única coisa que um gerenciador de pacotes deveria fazer bem.

Uma coisa que você pode fazer com PEAR e não com Composer é instalar extensões PECL . No entanto, existe a pickle que usa Composer e permite definir dependências de extensões nativas PHP em seu arquivo composer.json. O projeto de picles está momentaneamente passando por algum desenvolvimento e ainda não deve ser considerado maduro, mais já é possivel de ser usado e considerado.

A propósito, você pode usar o Composer para instalar os pacotes PEAR também

COMPOSER um gerenciador de pacotes para o PHP

Composer é uma ferramenta para gerenciamento de dependências em PHP, que permite que você declare as bibliotecas das quais seu projeto necessita e as gerenciará fazendo a instalação e atualização para você.  Com o Composer, você pode instalar os pacotes por projeto ou globalmente.

Quando você instala um PACOTE para um projeto, o composer, cria um diretório “vendor” dentro da pasta do projeto, e coloca os arquivos necessários lá, lembre-se que esses pacotes também podem precisar de outros pacotes e tudo será instalado da maneira correta, na versão correta, e permite que você faça a atualização de todas as dependências de maneira automática, através de um único comando.

Para instalar o composer, procure a documentação no site oficial: https://getcomposer.org/

Os pacotes seguem uma nomenclatura simples, composta pelo nome do desenvolvedor, seguido do nome do pacote, por exemplo:  pode ser nomeado como romeug/json e outro pode ser seldaek/json. Todas as necessidades do composer, são definidas em um arquivo que deve ficar na raiz do projeto, chamado composer.json, com uma estrutura similar a:

{
    "require": {
        "monolog/monolog": "2.0.*"
    }
}

Este arquivo indica que é requerido o pacote monolog/monolog e que sua versão deve ser 2.0.* que indica que qualquer versão minor da série 2.0 deve ser aceita. O composer usa um padrão de versionamento que é amplamente aceito, e que em breve teremos um artigo somente falando sobre esse assunto. O COMPOSER mapeia esse arquivo e busca dentro dos repositórios registrados qualquer conteúdo que satisfaça.

Apos as dependências, ao rodar o comando composer update um outro arquivo chamado composer.lock é criado, quando esse comando é executado, ele resolve as dependências e interdependências dos pacotes, bloqueando-os para versões específicas, e fazendo com que todas as pessoas que incluírem seu projeto como dependência ou instalem seu projeto, tenham as mesmas versões baixadas e instaladas em sua pasta vendor.

O próprio composer, pode gerar o arquivo de autoloader.php para carregar automaticamente todas as dependências, além de ser permissivo para o gerenciamente e manutenção do código.

Entendendo as EXTENSÕES do PHP

Agora que você já sabe como funcionam as extensões e bibliotecas prontas, vamos entender algumas das extensões que adicionam recursos ao core do php, se você rodar a função phpinfo(); vai obter uma visualização completa do ambiente, e das extensões disponíveis, suas versões e também detalhes da configuração atual do PHP, como estará disponível para você naquele ponto.

Essas extensões que apresentaremos hoje, são as extensões da PECL (pickle) que alteram diretamente o funcionamento do PHP, ou seja, que alteram diretamente a forma como o CORE lida com algumas funcionalidades. A maioria delas é destinada a CACHE e DEBUGGER e CONTROLE DE FLUXO DE SAÍDA. Nas proximas aulas, vamos continuando e apresentando outras extensões afim de cobrir todo o leque documentado de ferramentas externas.

APC e APCu – Cache de OPCODE

APCu é a substituição oficial da extensão APC que ficou depreciada ou desatualizada, e que fornecia cache de opcode (opcache) e cache de objetos, porém como o PHP 5.6 e mais novas trouxeram suas proprias ferramentas de opcache, a APC não era mais compatível e sua funcionalidade se tornou inútil. Os desenvolvedores do APC então criaram o APCu, que oferece apenas a funcionalidade de cache de objetos, ou seja “cache de dados na memória”.

APCu é um armazenamento no formato de chave:valor na memória, onde as chaves são string e os valores podem ser quaisquer variáveis ​​PHP existentes. Para habilita-la é necessário habilitar o módulo apcu.so (apcu.dll se for no windows) através do PHP.ini e as diretrizes abaixo, fazem o controle de como será o funcionamento da extensão. Embora as configurações padrão da APCu sejam adequadas para muitas instalações, usuários mais específicos ou serviços devem considerar o ajuste dos parâmetros, configurando pelo menos o quanto de memória será alocada ao APCu.

Assim que o servidor estiver em execução com a extensão habilitada, o script apc.php que vem junto com a extensão deve ser copiado em algum lugar para ser acessado e serve como um monitoramento e uma análise detalhada do funcionamento interno do APCu. Se o GD estiver habilitado no PHP, ele até exibirá alguns gráficos interessantes. Se o APCu estiver funcionando, o número de contagem total do cache exibirá o número de vezes que o cache atingiu a capacidade máxima e teve que limpar à força todas as entradas que não foram acessadas nos últimos apc.ttl segundos. Esse número é minimizado em um cache bem configurado, pois se o cache estiver sendo constantemente preenchido e liberado à força, a movimentação dos dados em memória terá efeitos ruins no desempenho. Neste ultimo caso, a maneira mais fácil de minimizar esse número é alocar mais memória para o APCu.

Nome Padrão Onde é definido O que faz
apc.enabled “1” PHP INI Habilita ou desabilita o cache
apc.shm_segments “1” PHP_INI O número de segmentos de memória compartilhada a serem alocados para o cache do compilador. Se o APC estiver ficando sem memória compartilhada, mas apc.shm_size estiver definido tão alto quanto o sistema permitir, aumentar esse valor pode impedir que o APC esgote sua memória.
apc.shm_size “32M” PHP_INI O tamanho de cada segmento de memória compartilhada fornecido por uma notação abreviada. Por padrão, alguns sistemas (incluindo a maioria das variantes do BSD) têm limites muito baixos no tamanho de um segmento de memória compartilhada.
apc.entries_hint “4096” PHP_INI Uma “dica” sobre o número de variáveis ​​distintas que podem ser armazenadas. Defina como zero ou omita se não tiver certeza.
apc.ttl “0” PHP_INI O número de segundos que uma entrada de cache pode ficar inativa em um slot, caso esse slot de entrada de cache seja necessário para outra entrada. Deixar isso em zero significa que o cache do APC pode potencialmente ficar cheio de entradas obsoletas, enquanto as entradas mais recentes não serão armazenadas em cache. No caso de um cache ficar sem memória disponível, o cache será completamente eliminado se ttl for igual a 0. Caso contrário, se o ttl for maior que 0, o APC tentará remover as entradas expiradas. Um valor ideal é algo que mantenha o cache proximo ao limite, sem no entanto manter entradas obsoletas registradas.
apc.gc_ttl “3600” PHP_INI O número de segundos que uma entrada de cache pode permanecer na lista de coleta de lixo. Este valor fornece uma proteção contra falhas no caso de um processo do servidor ser interrompido durante a execução de um arquivo de origem em cache; se esse arquivo de origem for modificado, a memória alocada para a versão antiga não será recuperada até que este TTL seja atingido. Defina como zero para desativar este recurso.
apc.mmap_file_mask NULL PHP_INI
Se compilado com suporte MMAP usando –enable-mmap, este é o file_mask no estilo mktemp para passar para o módulo mmap para determinar se sua região de memória mmap será apoiada por arquivo ou memória compartilhada. Para mmap de arquivo simples, defina-o para algo como /tmp/apc.XXXXXX (exatamente 6 Xs). Para usar shm_open / mmap no estilo POSIX, coloque um .shm em algum lugar da sua máscara. por exemplo. /apc.shm.XXXXXX Você também pode configurá-lo para / dev / zero para usar a interface / dev / zero do kernel para memória anônima com mapeamento mmap. Deixá-lo indefinido forçará um mmap anônimo.
apc.slam_defense “1” PHP_INI
Em servidores muito ocupados, sempre que você inicia o servidor ou modifica arquivos, pode criar uma corrida de muitos processos, todos tentando armazenar em cache o mesmo arquivo ao mesmo tempo. Esta opção define a porcentagem de processos que deixarão de tentar armazenar em cache um arquivo não armazenado em cache. Ou pense nisso como a probabilidade de um único processo ignorar o armazenamento em cache. Por exemplo, definir apc.slam_defense como 75 significa que há 75% de chance de que o processo não armazene em cache um arquivo sem cache, o que é uma ótima opção. Portanto, quanto maior a configuração, maior será a defesa contra cache slams. Definir como 0 desativa este recurso, o que não é a melhor opção.
apc.enable_cli “0” PHP_INI Principalmente para teste e depuração. Definir isso habilita o APC para a versão CLI do PHP. Em circunstâncias normais, não é ideal criar, preencher e destruir o cache APC em cada solicitação CLI, mas para vários cenários de teste, é útil ser capaz de habilitar o APC para a versão CLI do PHP facilmente.
apc.use_request_time “0” PHP_INI e EXECUÇÃO Use a hora de início da solicitação SAPI para TTL.
apc.serializer “php” PHP_INI Usado para configurar o APC para usar um serializador de terceiros.
apc.coredump_unmap “0” PHP_INI Permite o manuseio de sinais por APC, como SIGSEGV, que gravam arquivos principais quando sinalizados. Quando esses sinais são recebidos, o APC tentará desmapear o segmento de memória compartilhada para excluí-lo do arquivo principal. Esta configuração pode melhorar a estabilidade do sistema quando sinais fatais são recebidos e um grande segmento de memória compartilhada APC é configurado.
Este recurso é potencialmente perigoso. O desmapeamento do segmento de memória compartilhada em um manipulador de sinal fatal pode causar um comportamento indefinido se ocorrer um erro fatal. Embora alguns kernels possam fornecer um recurso para ignorar vários tipos de memória compartilhada ao gerar um arquivo de despejo de núcleo, essas implementações também podem ignorar segmentos de memória compartilhada importantes, como o placar do Apache.
apc.preload_path null PHP_INI Opcionalmente, defina um caminho para o diretório em que o APC carregará os dados do cache na inicialização.

Esta extensão define algumas CONSTANTES MÁGICAS que podem auxiliar na hora de fazer uso de suas funções durante a execução, lembre-se esses valores só estão disponíveis se a extensão estiver habilitada. São elas: APC_ITER_ALL (int), APC_ITER_ATIME (int), APC_ITER_CTIME (int), APC_ITER_DEVICE (int), APC_ITER_DTIME (int), APC_ITER_FILENAME (int), APC_ITER_INODE (int), APC_ITER_KEY (int), APC_ITER_MD5 (int), APC_ITER_MEM_SIZE (int), APC_ITER_MTIME (int), APC_ITER_NONE (int), APC_ITER_NUM_HITS (int), APC_ITER_REFCOUNT (int), APC_ITER_TTL (int), APC_ITER_TYPE (int), APC_ITER_VALUE (int), APC_LIST_ACTIVE (int), APC_LIST_DELETED (int). E que podem ser usadas como parâmetros para algumas funções da extensão, ou combinadas como as constantes mágicas nativas do PHP. Agora vamos falar sobre cada uma das funções da APCu, e explicar como utiliza-las e para que servem.

As FUNÇÕES DA APCu

apcu_enabled() – Indica se o APCu pode ou não ser usado no ambiente atual, retorna TRUE caso possa ser usado (habilitado) e FALSE se não puder ser habilitado.

apcu_add('CHAVE', $var, $ttl) — Adiciona uma nova variável ao cache, somente se esta ainda não estiver armazenada. Armazene a variável usando o nome definido em “CHAVE”, onde cada entrada é exclusiva, portanto, tentar usar apcu_add para armazenar dados com uma chave que já existe não substituirá os dados existentes e, em vez disso, retornará falso. $VAR é a variavel do PHP que será armazenada, podem ser armazenadas quaisquer variáveis serializáveis. TTL define os segundos em que essa variável estara disponível, depois que o ttl tiver passado, a variável armazenada será eliminada do cache na próxima solicitação, ou se for fornecido 0, o valor persistirá até que seja removido do cache manualmente ou, de outra forma, deixe de existir no cache como limpar, reiniciar o cache ou a máquina. A função retorna TRUE caso o valor tenha sido armazenado, ou FALSE em caso de erro.

apcu_store("CHAVE",$var, $ttl) – Do mesmo modo que a função add funciona, porém, se o valor já existir, ele será atualizado pelos novos valores passados. A função retorna TRUE caso o valor tenha sido armazenado, ou FALSE em caso de erro.

apcu_delete(“CHAVE”) ou apcu_delete(array(“chave1”, “chave2”, …, “chaveN”)); – Eliminas a chave ou as chaves indicadas, você também pode usar um ITERATOR, mais veremos isso adiante. Retorna TRUE ou um ARRAY com valores TRUE/FALSE para cada chave que será excluída.

apcu_exists("chave1") – Checa se existe a chave armazenada no cache, da mesma forma você pode passar um array com várias chaves/valores para checar se todos existem. O retorno, neste caso é um TRUE para chave existente ou FALSE para não existente, no caso de um array ter sido passado, o retorno é um ARRAY contendo as chaves existentes, ou um array vazio caso nenhuma delas esteja definida.

apcu_fetch("CHAVE", &$success ) – Retorna o valor da variavel armazenada no cache, ou NULL se não tiver valor correspondente a chave. O Parâmetro passado obrigatoriamente por referência seta TRUE caso a variável exista, e FALSE caso não exista. No caso de um array de chaves ter sido passado como primeiro argumento, o retorno é um array contendo os valores ou o valor NULL caso algum valor não exista. Neste segundo caso, false só será retornado se NENHUM valor existir no armazenamento.

apcu_cas("CHAVE", (int)$old, (int)$new) – Atualiza um VALOR ANTIGO (OLD) com o VALOR NOVO (NEW), caso o valor não exista, não será atualizado e a função vai retornar FALSE, caso o valor tenha sido atualizado, então, o retorno da função será TRUE. Lembre-se que esta função só funciona com valores armazenados do tipo INTEIRO (int), para outros tipos de valores você deve usar a função apcu_store() citada acima.

apcu_inc("CHAVE", (int) $step = 1, &$success, $ttl) – Incrementa um valor em +STEP, caso a chave não exista, será criada com o TTL informado e o valor retornado, caso não seja possivel criar, a função retorna FALSE, e caso tenha sido alterado retorna o NOVOVALOR da iteração. Caso o valor armazenado não seja inteiro, a variável passada por referência será setada para FALSO e caso contrário será TRUE.

apcu_dec("CHAVE", (int) $step = 1, &$success, $ttl) – Decrementa um valor em -STEP, caso a chave não exista, será criada com o TTL informado e o valor retornado, caso não seja possivel criar, a função retorna FALSE, e caso tenha sido alterado retorna o NOVOVALOR da iteração. Caso o valor armazenado não seja inteiro, a variável passada por referência será setada para FALSO e caso contrário será TRUE.

apcu_entry("CHAVE", callable $generator, $ttl) – Atomicamente tenta encontrar a chave no cache, se não puder ser encontrada, o gerador é chamado, passando a chave como único argumento. O valor de retorno da chamada é então armazenado em cache com o ttl opcionalmente especificado e retornado. Quando o controle entra em apcu_entry(), o bloqueio para o cache é adquirido exclusivamente, ele é liberado quando o controle sai de apcu_entry(). Na verdade, isso transforma o corpo do gerador em uma seção crítica, impedindo dois processos de executar os mesmos caminhos de código simultaneamente. Além disso, proíbe a execução simultânea de quaisquer outras funções APCu, uma vez que elas irão tentar adquirir o mesmo bloqueio.

apcu_key_info("CHAVE") – Retorna um array com as informações da chave informada ou null caso a chave não exista. O array contém as chaves:valores referentes aos dados daquele armazenamento. As chaves do array de retorno são ‘hits’ o número de vezes que ela foi recuperada, ‘access_time’ o timestamp da ultima vez que ela foi recuperada, mtime o timestamp da ultima atualização, creation_time o timestamp da hora que ela foi criada, deletion_time o horário que ela foi excluída ou deixou de ser válida pelo ttl. refs o número de referências ou atualizações que ela sofreu, ttl o tempo definido em segundos calculado a partir de mtime (mtime + ttl segundos) para o fim da vida da variável, ou para nova atualização.

apcu_cache_info(TRUE/FALSE) – Retorna um array com o estado atual do cache, se o valor informado na chamada for true, o array contém uma entrada individual para cada variável armazenada no cache, se for false, somente as informações globais do cache são retornadas. A função pode retornar FALSE, caso o cache não esteja habilitado ou tenha ocorrido alguma falha, como o bloqueio do cache por alguma função. Esta função tem basicamente a utilidade de servir como um monitoramento do estado atual do cache, para uma estatística ou verificação da necessidade de alterar as configurações ou outras iterações.

apcu_sma_info(TRUE/FALSE) – Retorna um array com informações da memória alocada, caso o valor passado seja FALSE somente as informações de memória principal são informadas, caso seja TRUE as informações de cada segmento/arquivo será indicada em blocos separados. Esta é outra função, que tem como objetivo monitorar a necessidade de ajustes nas configurações do cache.

apcu_clear_cache() – Faz a limpeza total do cache, ou seja, desaloca tudo e libera toda a memória novamente. Util, caso o administrador encontre problemas ou a memória disponível esteja cheia ou armazenando dados obsoletos. Esta função sempre retorna o valor TRUE, pois sempre que ela estiver disponível o cache está habilitado e a sua chamada vai remover todos os dados existentes, deixando o cache pronto para uso.

A classe APCUIterator

A classe APCUIterator torna mais fácil iterar em grandes caches APCu. Isso é útil porque permite a iteração em etapas, enquanto obtém um número definido de entradas por instância de bloqueio, de modo que libera os bloqueios de cache para outras atividades em vez de segurar o cache inteiro para capturar 100 (o padrão) entradas. Além disso, o uso de correspondência de expressão regular é mais eficiente, pois foi movido para o nível do SO ou linguagem C que é extremamente rápida.

APCUIterator::__construct(array|string|null $search = null, int $format = APC_ITER_ALL, int $chunk_size = 100, int $list = APC_LIST_ACTIVE); – Este é o construtor da classe, onde SEARCH é uma expressão regular PCRE que corresponde aos nomes de chave APCu, fornecidos como string. Ou uma matriz de strings com nomes de chaves APCu. Ou, opcionalmente, nulo para pular a pesquisa. O segundo argumento recebe uma das constantes mágicas referenciando o tipo de valor a ser percorrido, ou todos os tipos, ou alguma combinação deles. $CHUNK_SIZE determina o número de variaveis que ele deve retornar, onde 100 é o padrão. O ultimo argumento indica se deve retornar os ATIVOS (APC_LIST_ACTIVE) ou (APC_LIST_DELETED) para os deletados ou vencidos.

APCUIterator::current() – Retorna o item corrente do iterator, ou FALSE caso não exista mais iteradores ou ocorra uma falha na obtenção o cache.

APCUIterator::getTotalCount() – Retorna o número de interadores/itens disponíveis no cache. Ou FALSE em caso de falha.

APCUIterator::getTotalHits() – Número total de chamadas aos iteradores, ou FALSE em caso de falha.

APCUIterator::getTotalSize() – Retorna o tamanho em bytes do cache atual, ou FALSE em caso de falha, 0 em caso de vazio.

APCUIterator::key() – Retorna o nome da chave atual, null caso não tenha chave atual ou FALSE em caso de falha.

APCUIterator::next() – Move o ponteiro interno do iterator para o próximo item, ou FALSE em caso de atingir o final ou de falha.

APCUIterator::rewind() – Retorna o ponteiro do Iterator para o primeiro item, ou FALSE em caso de falha.

APCUIterator::valid() – Retorna TRUE caso a posição atual seja válida ou FALSE caso não seja.

Note, a Classe ACPUIterator não é totalmente documentada pela documentação oficial do PHP, onde somente a lista de argumentos está disponível e poucos exemplos.

Os melhores cenários de uso de um CACHE DE MEMÓRIA como o da APCu é para reduzir o gargalo de determinados pontos do sistema, por exemplo as ultimas notícias em um site de jornal, podem ser facilmente cacheadas e servidas de maneira estática, evitando um grande número de requisições ao banco de dados. O custo de processamento para implementar um cache de dados que sofrem pouca modificação ao longo de digamos 1 dia, ´e extremamente menor que a recarga desses dados seja ele de um banco de dados, ou de uma requisição a uma API externa.

Deixe um Comentário