12
respostas

Usar array ou objeto?

Olá, estou com uma dúvida gigante em visando melhor performance e qualidade de código se devo usar objeto ou array. Por exemplo, estou desenvolvendo uma aplicação que consome webservices e banco de dados e seus retornos são convertidos em arrays associativos e em algumas partes preciso comparar valores. Nesse caso qual seria a melhor alternativa, continuo usando array ou devo converter em objeto? LI em algum lugar algo que array é criado uma copia e objeto é passado por referencia, seria isso mesmo?

12 respostas

Eu acho que a melhor alternativa é fazer um array de objetos. Cada dado recebido, você converte em objeto e depois de um push em um array dos dados recebidos. Se você puder mostrar um exemplo dos dados que você recebe na aplicação e depois um exemplo de como pretendo compará-los acho que ficaria mais claro para chegarmos em uma solução ;D

Pra ficar ainda melhor usar JSon para troca de informações entre o APP e o WebService

Olá meu método principal e mais ou menos assim:

public function getUsersNeverAccess($idCourse)
    {
        $users = $this->getEnrolledUsers($idCourse);
        $data = array();
        $qtdUsers = count($users);

        for ($i = 0; $i < $qtdUsers; $i++) {

            if ($this->verifyUser($users[$i]['id'])) {

                $results = $this->getUsersCouses($users[$i]['id']);
                $qtdAux = count($results);

                for ($j = 0; $j < $qtdAux; $j++) {

                    if ($results[$j]['id'] == $idCourse && $results[$j]['lastaccess'] == NULL) {
                        //outra logica aqui
                        break;
                    }

                }
                unset($results);
            }
        }
        return $data;
    }

o método getEnrolledUsers() retorna:

array(77) {
  [0]=>
  array(8) {
    ["id"]=>
    int(37)
    ["fullname"]=>
    string(12) "NOME COMPLETO"
    ["email"]=>
    string(17) "EMAIL"
    ["phone1"]=>
    string(11) "TELEFONE"
    ["department"]=>
    string(0) ""
    ["institution"]=>
    string(4) "SEDE"
    ["city"]=>
    string(8) "CIDADE"
  }
...
}

o método verifyUser() só compara o uma lista de usuários que não devem entrar nesse loop e em getUsersCouses() traz:

array(77) {
  [0]=>
  array(25) {
    ["id"]=>
    int(687)
    .....
    ["lastaccess"]=>
    int(1583492545)
  }
}

basicamente pego todo os alunos inscritos em um curso, depois para cada aluno eu vejo os cursos que ele esta inscrito e comparo o id do curso solicitante com os id dos cursos do aluno e com o lastaccess.

porem todos esses loops e comparação está deixando o relatório bem lento, a alguma maneira de melhorar usando objeto?

Fala, Rafael. Beleza?

Então, cara. Arrays no PHP são otimizados pra tudo e pra nada ao mesmo tempo, então eu evito a todo custo utilizá-los para representar informações do meu domínio.

No seu exemplo de código, muitas coisas podem ser melhoradas, mas pra isso uma análise completa do código seria necessária.

Eu começaria mudando a chamada do método getEnrolledUsers pra só retornar os usuários válidos pra não ser necessária a chamada (dentro de um loop) do método verifyUser.

Também separaria melhor minhas classes, extraindo esse método getEnrolledUsers pra um repositório, etc.

Há muitas melhorias pra fazer, sempre, mas pra saber quais pontos específicos podem ser melhorados, uma análise mais completa seria necessária.

Dá uma olhada no curso de XDebug (fazendo todos os cursos de OO e seus pré-requisitos, claro), mais especificamente na parte de profiling. Aí analisa qual parte do seu relatório tá levando mais tempo e otimiza ela.

:-D

Abraços e bons estudos.

Olá Vinicius, obrigado pelo retorno. ainda não cheguei nesse curso, estou no de TDD ainda, mas fazendo alguns teste observei que a parte mais lenta e no segundo loop pois o array de comparação muitas vezes tem muitos índices e isso para cada aluno do curso.

Vou refatorar esse projeto e ver o que consigo melhorar com base no curso que indicou, obrigado.

Dando uma segunda olhada no seu código dá pra ver que ele tá bem procedural, e não orientado a objetos. =/

Além disso, depois de buscar os usuários você busca esse relacionamento (que não entendi o que é): $results = $this->getUsersCouses($users[$i]['id']);

O ideal era no seu repositório de usuários já buscar os usuários com esse relacionamento preenchido, nesse caso. Provavelmente já ajudaria um pouco. Aí essa "outra lógica" provavelmente seria extraída pra classe referente a esse relacionamento com usuário, entende?

como estou usando webservices sem acesso ao banco de dados não consigo fazer esse relacionamento, o método:

$results = $this->getUsersCouses($users[$i]['id']);

retorna todos os cursos que o aluno está inscrito com informações adicionais como ultimo acesso e se ele efetuou ou não alguma atividade. Preciso encontrar nesse array o id que seja igual do curso solicitante para poder fazer esse relacionamento.

Conseguir consegue sim, Rafael.

O mecanismo de persistência (de onde os dados vêm) é um mero detalhe pro código.

Se vem do banco, api, de um arquivo, da memória, tanto faz.

A modelagem é totalmente possível.

Interessante, sei que foge completamente do tópico, mas poderia me dar um exemplo bem simples de como posso fazer um relacionamento recebendo dados em json de uma api? ou algum norte nesse sentindo?

Fala, Rafael.

Sobre o norte, recomeondo estudar bastante sobre orientação a objetos, boas práticas, SOLID, Object Calisthenics, Elegant Objects, etc.

Um exemplo simples:

Você teria uma interface UserRepository:

interface UserRepository
{
    /** @return User[] */
    public function getEnrolledUsers(): array;

    // ... outros métodos necessários
}

E teria a implementação via API:

class ApiUserRepository
{
    private HttpClientAdapter $client;

    public function __construct(HttpClientAdapter $client)
    {
        $this->client = $client;
    }

    public function getEnrolledUsers(): array
    {
        // Mapeia um array de arrays para um array de objetos do tipo User
        $users = array_map(fn ($userAsArray) => $this->hidrateUser($user), $this->client->get('url/users');

        foreach ($user as $user) {
            $courses = $this->httpClient->get("url/courses/{$user->id()}");
            $user->addCourses($courses);
        }

        return $users;
    }
}

Obviamente esse pequeno pedaço de código é só de exemplo e possui inúmeros pontos de melhoria.

Se nem sempre você precisar dos cursos de um aluno, esse código desperdiça recursos.

Além disso, você pode utilizar algum cliente HTTP (como Guzzle, ReactPHP ou curl_multi_init) que permita fazer múltiplos requests simultâneos, assim você ganharia muito tempo.

Além dessas pequenas modificações, ainda recomendaria criar uma classe UserList para representar uma lista de usuários ao invés de utilizar arrays puros.

Olá Vinicius, realmente ajudou muito esse bloco de código, já tive uma ideia boa de como implementar algo parecido. Estou iniciando em desenvolvimento e me sinto muito perdido nesses assuntos, agradeço pelas explicações.

Eu sei como é. Eu também ficava mega perdido pra montar uma arquitetura.

Não tem segredo. A chave é estudar muito. Eu levei bastante tempo porque perdi tempo estudando as coisas erradas.

Esse guia te dá um bom começo: https://cursos.alura.com.br/guia-do-programador-php-vinicius-dias-p2779 (acompanha ele porque de vez em quando eu coloco conteúdo/curso novo)

Depois foca bastante em OO, boas práticas, e aqueles termos que citei na mensagem anterior.

:-D