Criando e Executando um Projeto Zend Framework (Laminas) no ServBay
Visão Geral
Zend Framework (atualmente parte do Laminas Project) é um robusto framework PHP open source que oferece uma gama de componentes orientados a objetos de alta qualidade, projetados para construção de aplicações e serviços web modernos. Reconhecido por sua flexibilidade, design modular e alto desempenho, é uma escolha ideal para criar desde sites simples até sistemas corporativos complexos.
O ServBay é um ambiente local de desenvolvimento web para macOS, integrando PHP, múltiplos servidores web (como Caddy e Nginx), bancos de dados (como MySQL, PostgreSQL, MongoDB), serviços de cache (como Redis, Memcached) e várias outras ferramentas para desenvolvedores. O ServBay facilita a configuração e o gerenciamento desses pacotes, tornando a criação e execução de projetos PHP localmente muito mais simples.
Este documento irá guiá-lo na criação e execução de um projeto Zend Framework (Laminas) no ServBay, além de demonstrar como integrar os bancos de dados e serviços de cache fornecidos pelo ServBay.
Pré-requisitos
Antes de começar, certifique-se de que você já:
- Instalou o ServBay: O ServBay está corretamente instalado e funcionando no seu macOS. Caso não tenha feito isso, acesse o site oficial do ServBay para obter instruções de download e instalação.
- Pacotes no ServBay: Confirme que você instalou e está rodando os pacotes necessários no ServBay, incluindo:
- Pelo menos uma versão do PHP (recomendado PHP 8.x ou superior, pois versões recentes do Zend Framework / Laminas requerem PHP moderno).
- Servidor web (Caddy ou Nginx).
- Composer (já incluso normalmente no ServBay).
- Bancos de dados e serviços de cache que você planeja usar (por exemplo, MySQL, PostgreSQL, Memcached, Redis). Você pode iniciar facilmente esses serviços pelo painel do ServBay.
Criando um Projeto Zend Framework
O ServBay recomenda que todos os seus projetos de site estejam na pasta /Applications/ServBay/www
, o que facilita a gestão e configuração automática dos sites.
Acesse o diretório raiz dos sites
Abra o terminal e navegue para o diretório sugerido:
bashcd /Applications/ServBay/www
1Crie o projeto com o Composer
O Composer já vem pré-instalado no ServBay, então não é necessário instalar separadamente. Crie um novo projeto Zend Framework (aplicação básica do Laminas) com o comando abaixo. O projeto será criado em um subdiretório chamado
servbay-zend-app
:bashcomposer create-project laminas/laminas-skeleton-application servbay-zend-app
1Isso irá baixar a aplicação base do Zend Framework (Laminas) para o diretório
servbay-zend-app
e instalar todas as dependências necessárias.Entre no diretório do projeto
Navegue até o diretório criado:
bashcd servbay-zend-app
1
Configurando o Servidor Web
Para acessar seu projeto Zend Framework via navegador, é preciso configurar um Website no ServBay.
- Abra o Painel do ServBay: Inicie o aplicativo ServBay.
- Acesse as configurações de Sites: No painel, clique na aba Sites (Websites).
- Adicione um novo site: Clique no botão “+” no canto inferior esquerdo para adicionar um novo site.
- Preencha as informações do site:
- Nome (Name): Dê um nome de fácil identificação, exemplo:
My Zend Dev Site
. - Domínio (Domain): Insira o domínio pelo qual você irá acessar o projeto no navegador. Para evitar conflitos, use um domínio terminando em
.local
ou.test
, por exemplo,servbay-zend-test.local
. O ServBay irá configurar o DNS local automaticamente. - Tipo do Site (Website Type): Selecione
PHP
. - Versão do PHP (PHP Version): Escolha a versão desejada para esse site (por exemplo,
8.3
). Certifique-se de que essa versão já está instalada e ativa no ServBay. - Raiz do documento (Document Root): Aponte para o diretório público do seu projeto, pois o arquivo de entrada
index.php
do Zend Framework fica empublic
. Portanto:/Applications/ServBay/www/servbay-zend-app/public
.
- Nome (Name): Dê um nome de fácil identificação, exemplo:
- Salve e reinicie: Clique em Salvar (Save). O ServBay irá pedir para aplicar as alterações; confirme e o servidor web irá recarregar, ativando o novo site.
Para detalhes, consulte a seção Adicionando seu primeiro site na documentação do ServBay.
Exemplo Básico "Hello ServBay!"
Agora, vamos alterar o projeto para exibir “Hello ServBay!” ao acessar a URL raiz (/
).
Configurar rotas e controlador (
module.config.php
)Edite o arquivo
module/Application/config/module.config.php
do projeto. Certifique-se de que ele contém as configurações básicas abaixo:php<?php declare(strict_types=1); namespace Application; use Laminas\Router\Http\Literal; use Laminas\Router\Http\Segment; use Laminas\ServiceManager\Factory\InvokableFactory; return [ 'router' => [ 'routes' => [ 'home' => [ 'type' => Literal::class, 'options' => [ 'route' => '/', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'index', ], ], ], // ... outras rotas ], ], 'controllers' => [ 'factories' => [ Controller\IndexController::class => InvokableFactory::class, ], ], 'view_manager' => [ 'display_not_found_reason' => true, 'display_exceptions' => true, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => [ 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ], 'template_path_stack' => [ __DIR__ . '/../view', ], ], // ... outras configurações ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49Nota: O bloco acima é apenas parte do
module.config.php
; integre esta configuração ao array existente. Assegure-se de que existam a rota'home'
e a fábrica paraController\IndexController::class
.Criar ou modificar o controlador (
IndexController.php
)Edite ou crie
module/Application/src/Controller/IndexController.php
. O métodoindexAction
deve retornar um ViewModel com a mensagem:php<?php declare(strict_types=1); namespace Application\Controller; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; class IndexController extends AbstractActionController { /** * Ação padrão - exibe a página de boas-vindas. */ public function indexAction() { // Retorna um ViewModel, passando a variável 'message' para a view return new ViewModel([ 'message' => 'Hello ServBay!', ]); } // ... outras ações }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24Criar ou modificar o arquivo de view (
index.phtml
)Edite ou crie
module/Application/view/application/index/index.phtml
, que receberá e exibirá a variávelmessage
:php<h1><?php echo $this->message; ?></h1>
1Aqui, o helper de view
$this->message
acessa os dados passados pelo controlador.
Acessando o Site
Abra o navegador e acesse o domínio configurado, por exemplo: https://servbay-zend-test.local
.
Se tudo estiver correto, a página exibirá Hello ServBay!
— indicando que seu projeto Zend Framework está rodando com sucesso no ServBay.
Exemplos de Integração com Banco de Dados e Cache
O ServBay oferece diversos bancos e serviços de cache. A seguir, exemplos de como conectar e utilizar Memcached, Redis, MySQL e PostgreSQL em projetos Zend Framework.
Atenção: Os exemplos abaixo são independentes. Em aplicações reais, normalmente uma combinação (um banco e um ou mais caches) é usada, com injeção de dependências gerenciando as conexões. Certifique-se de iniciar os serviços correspondentes no ServBay (MySQL, PostgreSQL, Memcached, Redis).
Exemplo de Interação com Banco de Dados – Criação de Tabela
Veja como usar o componente Laminas DB para interagir com o banco, criando uma tabela simples. O foco é demonstrar a operação, não usar o Laminas Migrations completo.
Instale o componente Laminas DB
No terminal, estando no diretório do projeto, execute:
bashcomposer require laminas/laminas-db
1Crie manualmente o banco de dados
Antes do exemplo funcionar, crie no gerenciador do ServBay um banco chamado
servbay_zend_app
. O usuário padrão MySQL/MariaDB éroot
e senhapassword
. Para PostgreSQL, tambémroot
/password
.Defina e execute o script de criação de tabela (exemplo)
Crie um arquivo
create_users_table.php
na raiz do projeto, com:php<?php // create_users_table.php use Laminas\Db\Adapter\Adapter; use Laminas\Db\Sql\Sql; // Supondo uso do MySQL ou MariaDB $adapter = new Adapter([ 'driver' => 'Pdo_Mysql', // Ou 'Pdo_Pgsql' 'database' => 'servbay_zend_app', 'username' => 'root', 'password' => 'password', // Senha padrão do ServBay 'hostname' => '127.0.0.1', // 'port' => 3306, // Porta padrão MySQL // 'port' => 5432, // Porta padrão PostgreSQL ]); $sql = new Sql($adapter); // Define SQL para criar tabela users $create = $sql->createTable('users') ->addColumn(new \Laminas\Db\Sql\Ddl\Column\Integer('id', false, null, ['AUTO_INCREMENT' => true])) ->addColumn(new \Laminas\Db\Sql\Ddl\Column\Varchar('name', 255)) ->addColumn(new \Laminas\Db\Sql\Ddl\Column\Varchar('email', 255, ['UNIQUE' => true])) ->addConstraint(new \Laminas\Db\Sql\Ddl\Constraint\PrimaryKey('id')); echo "Executando SQL:\n"; echo $sql->buildSqlString($create, $adapter->getPlatform()) . "\n"; try { // Executa o SQL $adapter->query( $sql->buildSqlString($create, $adapter->getPlatform()), Adapter::QUERY_MODE_EXECUTE ); echo "Tabela 'users' criada com sucesso.\n"; } catch (\Exception $e) { echo "Erro ao criar tabela: " . $e->getMessage() . "\n"; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38Nota: Este é um exemplo manual. Em projetos reais, recomenda-se usar o Laminas Migrations.
Execute o script com:
bashphp create_users_table.php
1
Exemplo de Integração com MySQL
Como conectar e consultar o MySQL a partir de um controlador Zend Framework.
Configurar conexão com banco
Edite
config/autoload/global.php
e adicione ou ajuste a configuração do MySQL:php<?php // config/autoload/global.php return [ 'db' => [ 'driver' => 'Pdo_Mysql', 'database' => 'servbay_zend_app', // Certifique-se que existe 'username' => 'root', // Usuário padrão 'password' => 'password', // Senha padrão 'hostname' => '127.0.0.1', 'port' => 3306, // Porta padrão MySQL 'charset' => 'utf8mb4', ], // ... outras configurações ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14Configurar fábrica do controlador (
module.config.php
)Para injeção do
Laminas\Db\Adapter\Adapter
no controlador, defina a factory. No arquivomodule/Application/config/module.config.php
, substitua ou adicione a fábrica para oIndexController
(se já houver InvokableFactory, troque):php<?php // module/Application/config/module.config.php namespace Application; use Laminas\ServiceManager\Factory\InvokableFactory; use Laminas\Db\Adapter\AdapterInterface; return [ // ... outras configurações 'controllers' => [ 'factories' => [ Controller\IndexController::class => function($container) { // Obtenha o Adapter do Service Manager $adapter = $container->get(AdapterInterface::class); return new Controller\IndexController($adapter); }, // Outras fábricas se necessário ], ], 'service_manager' => [ 'aliases' => [ // Alias para AdapterInterface AdapterInterface::class => 'Laminas\Db\Adapter\Adapter', ], 'factories' => [ // Factory do Adapter 'Laminas\Db\Adapter\Adapter' => \Laminas\Db\Adapter\AdapterServiceFactory::class, ], ], // ... outras configurações ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31Nota: Garanta que as seções
controllers
eservice_manager
estão corretas.Configurar rotas (
module.config.php
)Acrescente estas rotas em
module/Application/config/module.config.php
:php<?php // module/Application/config/module.config.php namespace Application; use Laminas\Router\Http\Literal; // ... outros use return [ 'router' => [ 'routes' => [ // ... rotas existentes 'mysql-add' => [ 'type' => Literal::class, 'options' => [ 'route' => '/mysql-add', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'mysqlAdd', ], ], ], 'mysql' => [ 'type' => Literal::class, 'options' => [ 'route' => '/mysql', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'mysql', ], ], ], ], ], // ... demais configurações ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35Adicionar métodos ao controlador (
IndexController.php
)No arquivo
module/Application/src/Controller/IndexController.php
, adicione construtor,mysqlAddAction
emysqlAction
:php<?php declare(strict_types=1); namespace Application\Controller; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; use Laminas\Db\Adapter\AdapterInterface; use Laminas\Db\Sql\Sql; class IndexController extends AbstractActionController { private $adapter; public function __construct(AdapterInterface $adapter) { $this->adapter = $adapter; } /** * Página inicial de boas-vindas. */ public function indexAction() { return new ViewModel([ 'message' => 'Hello ServBay!', ]); } /** * Adiciona um usuário na tabela 'users' via MySQL. */ public function mysqlAddAction() { $sql = new Sql($this->adapter); $insert = $sql->insert('users') ->values([ 'name' => 'ServBay Demo User', 'email' => '[email protected]', ]); $statement = $sql->prepareStatementForSqlObject($insert); $result = $statement->execute(); $message = $result->getAffectedRows() > 0 ? 'Usuário MySQL adicionado com sucesso.' : 'Falha ao adicionar usuário MySQL.'; return new ViewModel([ 'message' => $message, ]); } /** * Lista todos os usuários via MySQL. */ public function mysqlAction() { $sql = new Sql($this->adapter); $select = $sql->select('users'); $statement = $sql->prepareStatementForSqlObject($select); $result = $statement->execute(); $users = []; foreach ($result as $row) { $users[] = $row; } return new ViewModel([ 'users' => json_encode($users, JSON_PRETTY_PRINT), ]); } // ... outras ações }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75Criar arquivos de view
Crie
module/Application/view/application/index/mysql-add.phtml
:php<h1><?php echo $this->message; ?></h1>
1Crie
module/Application/view/application/index/mysql.phtml
:php<h1>Usuários MySQL</h1> <pre><?php echo $this->users; ?></pre>
1
2Testar os exemplos MySQL
Certifique-se de que o MySQL está ativo no ServBay. Primeiro acesse
https://servbay-zend-test.local/mysql-add
para adicionar um usuário. Deverá aparecer "Usuário MySQL adicionado com sucesso." Depois acessehttps://servbay-zend-test.local/mysql
para listar os usuários (em formato JSON).
Exemplo de Integração com PostgreSQL
Semelhante ao exemplo com MySQL, mas usando PostgreSQL.
Configurar conexão PostgreSQL
No
config/autoload/global.php
, coloque:php<?php // config/autoload/global.php return [ 'db' => [ 'driver' => 'Pdo_Pgsql', 'database' => 'servbay_zend_app', 'username' => 'root', 'password' => 'password', 'hostname' => '127.0.0.1', 'port' => 5432, // Porta padrão PostgreSQL ], // ... outras configurações ];
1
2
3
4
5
6
7
8
9
10
11
12
13Configurar fábrica do controlador
(Igual ao MySQL, caso já feito, não requeira alterações.)
Configurar rotas para PostgreSQL
Acrescente:
php<?php namespace Application; use Laminas\Router\Http\Literal; return [ 'router' => [ 'routes' => [ // ... rotas existentes 'pgsql-add' => [ 'type' => Literal::class, 'options' => [ 'route' => '/pgsql-add', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'pgsqlAdd', ], ], ], 'pgsql' => [ 'type' => Literal::class, 'options' => [ 'route' => '/pgsql', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'pgsql', ], ], ], ], ], ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32Adicionar métodos ao controlador
Em
IndexController
:php<?php declare(strict_types=1); namespace Application\Controller; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; use Laminas\Db\Adapter\AdapterInterface; use Laminas\Db\Sql\Sql; class IndexController extends AbstractActionController { private $adapter; public function __construct(AdapterInterface $adapter) { $this->adapter = $adapter; } // ... outros métodos /** * Adiciona usuário na tabela 'users' via PostgreSQL. */ public function pgsqlAddAction() { $sql = new Sql($this->adapter); $insert = $sql->insert('users') ->values([ 'name' => 'ServBay Demo User', 'email' => '[email protected]', ]); $statement = $sql->prepareStatementForSqlObject($insert); $result = $statement->execute(); $message = $result->getAffectedRows() > 0 ? 'Usuário PostgreSQL adicionado com sucesso.' : 'Falha ao adicionar usuário PostgreSQL.'; return new ViewModel([ 'message' => $message, ]); } /** * Lista usuários via PostgreSQL. */ public function pgsqlAction() { $sql = new Sql($this->adapter); $select = $sql->select('users'); $statement = $sql->prepareStatementForSqlObject($select); $result = $statement->execute(); $users = []; foreach ($result as $row) { $users[] = $row; } return new ViewModel([ 'users' => json_encode($users, JSON_PRETTY_PRINT), ]); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65Criar arquivos de view
module/Application/view/application/index/pgsql-add.phtml
:php<h1><?php echo $this->message; ?></h1>
1module/Application/view/application/index/pgsql.phtml
:php<h1>Usuários PostgreSQL</h1> <pre><?php echo $this->users; ?></pre>
1
2Testar os exemplos PostgreSQL
Certifique-se que o PostgreSQL está rodando no ServBay. Visite
https://servbay-zend-test.local/pgsql-add
para adicionar um usuário, e depoishttps://servbay-zend-test.local/pgsql
para listar os usuários.
Exemplo de Integração com Memcached
Demonstração de uso do Memcached para cache em um controlador Zend Framework.
Instalar adaptador Memcached
Em
composer.json
, garanta:json{ "require": { "laminas/laminas-skeleton-application": "^1.0", "laminas/laminas-cache-storage-adapter-memcached": "^2.0" } }
1
2
3
4
5
6E instale com:
bashcomposer update
1O ServBay já traz o PHP
memcached
extension instalado.Adicionar rota Memcached
Adicione em
module.config.php
:php'memcached' => [ 'type' => \Laminas\Router\Http\Literal::class, 'options' => [ 'route' => '/memcached', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'memcached', ], ], ]
1
2
3
4
5
6
7
8
9
10Adicionar método ao controlador
Em
IndexController.php
:phpuse Laminas\Cache\StorageFactory; use Laminas\Cache\Storage\StorageInterface; // ... /** * Exemplo de uso do Memcached. */ public function memcachedAction() { // Memcached padrão em 127.0.0.1:11211 $cache = StorageFactory::factory([ 'adapter' => [ 'name' => 'memcached', 'options' => [ 'servers' => [ ['127.0.0.1', 11211], ], 'ttl' => 300, // 5 minutos ], ], 'plugins' => [ 'serializer', 'exception_handler' => ['throw_exceptions' => false], ], ]); $cacheKey = 'my_memcached_data'; $cachedData = $cache->getItem($cacheKey, $success); if (!$success) { $cachedData = 'Hello Memcached! (Dado original, salvo em ' . date('Y-m-d H:i:s') . ')'; $cache->setItem($cacheKey, $cachedData); $cachedData .= ' - CACHE MISS'; } else { $cachedData .= ' - CACHE HIT'; } return new ViewModel([ 'message' => $cachedData ]); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40Criar arquivo de view
module/Application/view/application/index/memcached.phtml
:php<h1>Exemplo de Memcached</h1> <p><?php echo $this->message; ?></p>
1
2Testar Memcached
Com o Memcached ativo, acesse
https://servbay-zend-test.local/memcached
. O primeiro acesso deverá mostrar "CACHE MISS"; acessos subsequentes dentro do TTL mostrarão "CACHE HIT".
Exemplo de Integração com Redis
Para demonstrar uso de Redis para cache ou armazenamento.
Instalar adaptador Redis
Garanta em
composer.json
:json{ "require": { "laminas/laminas-skeleton-application": "^1.0", "laminas/laminas-cache-storage-adapter-redis": "^2.0", "ext-redis": "*" } }
1
2
3
4
5
6
7Instale via:
bashcomposer update
1O PHP
redis
extension já está incluso no ServBay.Adicionar rota Redis
Em
module.config.php
:php'redis' => [ 'type' => \Laminas\Router\Http\Literal::class, 'options' => [ 'route' => '/redis', 'defaults' => [ 'controller' => Controller\IndexController::class, 'action' => 'redis', ], ], ]
1
2
3
4
5
6
7
8
9
10Adicionar método ao controlador
Em
IndexController.php
:phpuse Laminas\Cache\StorageFactory; use Laminas\Cache\Storage\StorageInterface; // ... /** * Exemplo de uso do Redis. */ public function redisAction() { // Redis padrão em 127.0.0.1:6379 $cache = StorageFactory::factory([ 'adapter' => [ 'name' => 'redis', 'options' => [ 'server' => [ 'host' => '127.0.0.1', 'port' => 6379, ], 'ttl' => 300, // 5 minutos ], ], 'plugins' => [ 'serializer', 'exception_handler' => ['throw_exceptions' => false], ], ]); $cacheKey = 'my_redis_data'; $cachedData = $cache->getItem($cacheKey, $success); if (!$success) { $cachedData = 'Hello Redis! (Dado original, salvo em ' . date('Y-m-d H:i:s') . ')'; $cache->setItem($cacheKey, $cachedData); $cachedData .= ' - CACHE MISS'; } else { $cachedData .= ' - CACHE HIT'; } return new ViewModel([ 'message' => $cachedData ]); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41Criar arquivo de view
module/Application/view/application/index/redis.phtml
:php<h1>Exemplo de Redis</h1> <p><?php echo $this->message; ?></p>
1
2Testar Redis
Com Redis rodando, acesse
https://servbay-zend-test.local/redis
. Primeira vez deverá exibir "CACHE MISS"; nas seguintes dentro do TTL, "CACHE HIT".
Conclusão
Seguindo estes passos, você conseguiu criar, configurar e executar com sucesso um projeto Zend Framework (Laminas) no ambiente local do ServBay. Você aprendeu como apontar a raiz do servidor web para a pasta pública do projeto, e como integrar e utilizar os bancos MySQL, PostgreSQL, além do Memcached e Redis para cache.
O ServBay simplifica drasticamente a configuração e gerenciamento do ambiente local, permitindo que você foque mais no desenvolvimento do projeto em si. Com a variedade de pacotes e flexibilidade do ServBay, é fácil simular o ambiente de produção localmente e aumentar sua produtividade no desenvolvimento web.