Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

CleitonGarcia

Código extenso. Como "encurtar"?

Recommended Posts

Tenho o código abaixo que é para inclusão do arquivo de configurações do sistema. Utilizando cookies e banco de dados para recuperar os nomes das linguagens e seus respectivos arquivos!

 

O problema é que tenho 3 querys nesse mesmo arquivo. O que devo fazer pra diminuir as linhas desse código que eu sei que dá pra fazer drásticamente e assim então permanecer a eficácia do mesmo?

 

<?php

if (!isset ($_COOKIE["lang"]) && empty ($_COOKIE["lang"])){

	$query = $mysql->sql_query ("SELECT * FROM `{$prefix}langs` WHERE `file` = '" . DefaultLanguage. "'");
	$Language = mysql_fetch_array ($query);
	$count = mysql_num_rows ($query);

	if (empty ($count)){

		echo "Linguagem definida pelo arquivo de configurações é inexistente na database.";
		exit;

	} else {

		if (file_exists ("./langs/{$Language["file"]}.php")){

			require "./langs/{$Language["file"]}.php";
		
		} else {

			echo "Arquivo de linguagem não encontrada.";
			exit;

		}

	}

} else {

	$query = $mysql->sql_query ("SELECT * FROM `{$prefix}langs` WHERE `file` = '{$_COOKIE["lang"]}'");
	$Language = mysql_fetch_array ($query);
	$count = mysql_num_rows ($query);

	if (empty ($count)){

		$query = $mysql->sql_query ("SELECT * FROM `{$prefix}langs` WHERE `file` = '" . DefaultLanguage. "'");
		$Language = mysql_fetch_array ($query);
		$count = mysql_num_rows ($query);

		if (empty ($count)){

			echo "Linguagem definida pelo arquivo de configurações é inexistente na database.";
			exit;

		} else {

			if (file_exists ("./langs/{$Language["file"]}.php")){

				require "./langs/{$Language["file"]}.php";
			
			} else {

				echo "Arquivo de linguagem não encontrada.";
				exit;

			}

		}

	} else {

		if (file_exists ("./langs/{$Language["file"]}.php")){

			require "./langs/{$Language["file"]}.php";

		} else {

			echo "Arquivo de linguagem não encontrada.";
			exit;

		}

	}

}

 

Infelizmente ainda perco tempo com o paradigma procedural!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Em um código procedural isto é quase impossível, este código é extremamente complexa, e há muitas coisas para se fazer antes dessas queries, uma delas é utilizar Exceptions ao invés de echo + exit (gambiarra!) e NÃO USAR JAMAIS o mysql_* use Mysqli ou PDO, inclusive no PHP novo (5.5) estas funções foram depreciadas.

 

Essas queries parecem muito repetitivas, acho que tem algo muito errado na lógica, mas como eu disse, penso que somente orientação a objetos poderia reduzir este código quebrando em pequenas partes, até porque você está acoplado à um banco de dados etc.

 

Em um exemplo prático, veja como vc está repetindo lógica: Nas linhas 16, 48, e 63 você tem o mesmo código é está extremamente confuso.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Em um código procedural isto é quase impossível, este código é extremamente complexa, e há muitas coisas para se fazer antes dessas queries, uma delas é utilizar Exceptions ao invés de echo + exit (gambiarra!) e NÃO USAR JAMAIS o mysql_* use Mysqli ou PDO, inclusive no PHP novo (5.5) estas funções foram depreciadas.

 

Essas queries parecem muito repetitivas, acho que tem algo muito errado na lógica, mas como eu disse, penso que somente orientação a objetos poderia reduzir este código quebrando em pequenas partes, até porque você está acoplado à um banco de dados etc.

 

Em um exemplo prático, veja como vc está repetindo lógica: Nas linhas 16, 48, e 63 você tem o mesmo código é está extremamente confuso.

 

Sim o código está muito "avoado", repetido. Eu sei que este código tá um lixo. Infelizmente acredito que seja o máximo que o paradigma procedural possa fazer! Enquanto ao banco, eu estou criando uma classe em PDO. Fora isso, realmente somente OO para me salvar!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Fazendo uma pequena refatoração, tentando ainda não orientar a objeto, mas usando funções (uma evolução de cada vez).

 

Problemas:

 

- Vc está acoplado ao Mysql

- Vc está usando path relativo

- Como o código é procedural, vc tem estado global

- Repetição de código

- Erros tratados de forma terrível

- Alta complexidade (muitos ifs)

 

Refatorando:

 

function getDefaultLanguage()
{
    return 'en'; // substitua pela língua padrão
}

function getCookieLanguage()
{
    if (!isset($_COOKIE['lang'])) {
        return;
    }

    return $_COOKIE['lang'];
}

function getLanguage()
{
    $cookie = getCookieLanguage();

    if (null === $cookie) {
        return getDefaultLanguage();
    }

    return $cookie;
}

function getDatabaseConnectionData()
{
    // substitua pelos dados de conexão com a base
    return [
        'type' => 'mysql',
        'host' => 'localhost',
        'user' => 'root',
        'pass' => '',
        'name' => 'dbname',
        'charset' => 'UTF-8',
    ];
}

function getDatabaseConnection()
{
    $data = getDatabaseConnectionData();

    return new PDO(
        sprintf(
            '%s/dbname=%s;host=%s;charset=%s', $data['type'], $data['name'], $data['host'], $data['charset']
        ),
        $data['user'],
        $data['pass']
    );
}


function getLanguagePath()
{
    // substitua com o diretório dos arquivos de lingagem
    return __DIR__ . '/langs';
}

function getFileLanguageName($language)
{
    return sprintf('%s/%s.php', getLanguagePath(), $language);
}

function hasFileLangauge($language)
{
    return file_exists(getFileLanguageName($language));
}

function execute(PDO $pdo)
{
    $statement = $pdo->prepare('
        SELECT
            file
        FROM
            langs
        WHERE
            file=:language;
    ');

    $statement->setFetchmode(PDO::FETCH_OBJ);
    $statement->bindValue(':language', getLanguage(), PDO::PARAM_STR);

    if ($statement->execute()) {
        $language = $statement->fetch();

        $statement->closeCursor();
    }

    if (!count($language)) {
        throw new RuntimeException('Linguagem inexistente no banco de daods.');
    }

    return $language;
}

function includeLangFile($language)
{
    $file = $language->file;

    if (!hasFileLangauge($file)) {
        throw new LogicException('Arquivo de linguagem não encontrado.');
    }

    require_once getFileLanguageName($file);
}

try {
    includeLangFile(execute(getDatabaseConnection()));
} catch (Exception $e) {
    echo sprintf('Ocorreu um erro no sistema: %s', $e->getMessage());
}

 

 

Eu provavelmente errei bastante coisa neste código, até porque não consigo ter uma visão completa do software, por exemplo não entendo para que a utilização da base de dados, mas .. eu dei uma melhorada, não sei se o código funciona, devo ter cometido erros e não consigo testar pois não tenho a base nem os arquivos etc, mas fiz uma limpeza utilizando o mínimo de OO possível, criei tudo em funções, a parte OO é da PDO;

Compartilhar este post


Link para o post
Compartilhar em outros sites

Colega,

 

Eu tenho medo do procedural. Pena que sei programar apenas com ele. Sei pouca coisa ainda de OO (prática). Mas se este código estiver em OO, me ajudará imensamente. Você poderia fazer este grande favor?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Encurtar é uma palavra "ruim" para programação, utilize "refatorar".

 

Esse é um momento de leitura. Procure sobre refatoração de código, tem muito material didático por ai.

 

Existem alguns livros para se ter na cabeceira da sua cama, um deles é o Clean Code. Eu, particularmente, possuo ele. É excelente e de fácil leitura.

 

Existem outros autores que possuem livros do mesmo gênero, como Refactoring do Martin Fowler.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Desculpem a minha ignorancia no assunto, mas na solução proposta no post #5 o código me parece mais extenso que o original, a idéia não era o contrário? E pq usar echo + exit é tão abominável assim?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Thiago Moraes,

 

Encurtar código não significa melhorar, a solução que coloquei possui mais linhas de código sim, mas linhas limpas, flexíveis, reutilizáveis, testáveis e que não se repetem, você pode ter 500 linhas de código lindo e 50 linhas de um código horroroso.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas 500 linhas de código demanda mais recursos do que 50 certo? e supondo que não haja necessidade de reutilização do código.

 

Que fique bem claro que eu não estou querendo desmerecer sua solução, sou iniciante em php e apenas gostaria de entender melhor a questão de otimização.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não necessáriamente mais linhas significa menor ou mais desempenho. Tudo depende das funções que você usará no código. Fora isso, o que vai valer é o entendimento e por se dizer, beleza, ou seja, um código limpo, organizado, bem estruturado. Quantidade de linhas não significa completamente um código melhor. Um código maior pode ser melhor que um menor e vice-versa. Pra mim o que vale é o desempenho e organização, desempenho pra saber utilizar as funções, reutilizar os códigos e fazer de forma correta e eficaz, e organização por limpeza do código e entendimento do mesmo!

 

Sei muito bem que é muito pedir o código em OO deste algoritmo. Mas realmente iria me ajudar muito! :/

Compartilhar este post


Link para o post
Compartilhar em outros sites

quanto menos codigo menos dor de cabeça. rs.

Compartilhar este post


Link para o post
Compartilhar em outros sites

quanto menos codigo menos dor de cabeça. rs.

 

Sim e não. Sim pois vai depender da organização do seu código, se for organizado menos dor de cabeça. Não porque pois dependendo da organização aconselhando ao método de programação, seu código ficará organizado, mais complexo e refatorado. então não adiantará de nada. Veja meu código em procedural, é organizado (pra mim eu gosto), não é tão extenso, mas é complexo. Já o código da sugestão do colega, tem maior número de linhas, menos complexo (de certa forma), e com certeza 10x mais organizado, pois usou OO e outras coisinhas mais.

 

Então meu caro, depende de vários fatores pra ter menos dor de cabeça. Não é somente tamanho do código!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok, então vou minificar os códigos agora ...

 

Veja que código "lindo":

 

<?php if(isset($_POST['user'])&&$_POST['user']==='Nome'){echo 'Bem-vindo, usuário '.$_POST['user']}

 

 

Forma mais curta que consegui, mas código pequeno não significa bom.

 

Eu não usei OO no código da solução, usei apenas funções.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas 500 linhas de código demanda mais recursos do que 50 certo? e supondo que não haja necessidade de reutilização do código.

 

Que fique bem claro que eu não estou querendo desmerecer sua solução, sou iniciante em php e apenas gostaria de entender melhor a questão de otimização.

Pra você, o que são linhas de código? Indentar e espaçar um código-fonte não interfere em nada na performance, o parsing de caracteres ignorados é muitíssimo rápido. Para verificar alguma diferença de performance, você precisaria trocar cada quebra de linha do código em questão por, mais ou menos, 512mil quebras de linha (512k). Aí sim, vocẽ notaria uma pequena queda de performance. De fato, demanda mais recurso, uma vez que o tamanho em bytes do arquivo aumenta. Mas sem impacto na resposta final e com melhor aproveitamento/produtividade do programador.

 

Fazendo uma pequena refatoração, tentando ainda não orientar a objeto, mas usando funções (uma evolução de cada vez).

 

Problemas:

 

- Vc está acoplado ao Mysql

- Vc está usando path relativo

- Como o código é procedural, vc tem estado global

- Repetição de código

- Erros tratados de forma terrível

- Alta complexidade (muitos ifs)

 

Refatorando:

 

 




function getDefaultLanguage()
{
    return 'en'; // substitua pela língua padrão
}

function getCookieLanguage()
{
    if (!isset($_COOKIE['lang'])) {
        return;
    }

    return $_COOKIE['lang'];
}

function getLanguage()
{
    $cookie = getCookieLanguage();

    if (null === $cookie) {
        return getDefaultLanguage();
    }

    return $cookie;
}

function getDatabaseConnectionData()
{
    // substitua pelos dados de conexão com a base
    return [
        'type' => 'mysql',
        'host' => 'localhost',
        'user' => 'root',
        'pass' => '',
        'name' => 'dbname',
        'charset' => 'UTF-8',
    ];
}

function getDatabaseConnection()
{
    $data = getDatabaseConnectionData();

    return new PDO(
        sprintf(
            '%s/dbname=%s;host=%s;charset=%s', $data['type'], $data['name'], $data['host'], $data['charset']
        ),
        $data['user'],
        $data['pass']
    );
}


function getLanguagePath()
{
    // substitua com o diretório dos arquivos de lingagem
    return __DIR__ . '/langs';
}

function getFileLanguageName($language)
{
    return sprintf('%s/%s.php', getLanguagePath(), $language);
}

function hasFileLangauge($language)
{
    return file_exists(getFileLanguageName($language));
}

function execute(PDO $pdo)
{
    $statement = $pdo->prepare('
        SELECT
            file
        FROM
            langs
        WHERE
            file=:language;
    ');

    $statement->setFetchmode(PDO::FETCH_OBJ);
    $statement->bindValue(':language', getLanguage(), PDO::PARAM_STR);

    if ($statement->execute()) {
        $language = $statement->fetch();

        $statement->closeCursor();
    }

    if (!count($language)) {
        throw new RuntimeException('Linguagem inexistente no banco de daods.');
    }

    return $language;
}

function includeLangFile($language)
{
    $file = $language->file;

    if (!hasFileLangauge($file)) {
        throw new LogicException('Arquivo de linguagem não encontrado.');
    }

    require_once getFileLanguageName($file);
}

try {
    includeLangFile(execute(getDatabaseConnection()));
} catch (Exception $e) {
    echo sprintf('Ocorreu um erro no sistema: %s', $e->getMessage());
}

 

 

 

Eu provavelmente errei bastante coisa neste código, até porque não consigo ter uma visão completa do software, por exemplo não entendo para que a utilização da base de dados, mas .. eu dei uma melhorada, não sei se o código funciona, devo ter cometido erros e não consigo testar pois não tenho a base nem os arquivos etc, mas fiz uma limpeza utilizando o mínimo de OO possível, criei tudo em funções, a parte OO é da PDO;

 

 

 

 

Impossível não dar +1 para este post. Seu trabalho foi incrível! Eu ainda faria algumas ressalvas:

  • Não tente simplificar a DSN da PDO. Acredite, o máximo já foi feito. Você cita que o código está acoplado ao MySQL, mas a refatoração não serve para uma série de outros SGDB's.
  • Eu levaria todas as strings para o topo do arquivo/funções - ou, talvez, até mesmo um arquivo separado. Elas poderiam ser guardadas em variáveis ou constantes
  • Faria maior uso de ternários
  • A função execute possui um nome muito genérico sendo que seu conteúdo é especializado
  • Como não há uso de OO, faria uso da API de erros do PHP (trigger_error) ao invés de Exceções
  • <?php
    
    defined('__DIR__') or define('__DIR__', realpath(dirname(__FILE__)));
    define('LANGUAGES_DIRECTORY', __DIR__ . '/langs');
    
    const DEFAULT_LANGUAGE = 'en';
    const LANGUAGE_QUERY = 'select count(file) from languages where file = ?;';
    const DB_SERVER = 'mysql';
    const DB_LANGUAGE_ERROR = 'Linguagem inexistente no banco de dados.';
    const FILE_LANGUAGE_ERROR = 'Arquivo de linguagem não encontrado.';
    
    function getCookieLanguage($key = 'lang')
    {
        return in_array($key, $_COOKIE) ? $_COOKIE[$key] : DEFAULT_LANGUAGE;
    }
    
    /**
     * @param $server String
     * @param $args Array
     * @return PDO
     */
    function getDatabaseConnection($server, array $args = array())
    {
        $functionName = 'get' . ucfirst(strtolower($server)) . 'Pdo';
        /** @var $connection PDO */
        $connection = $functionName($args, false);
        $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        return $connection;
    }
    
    function getMysqlPdo(array $args = array(), $overrideCached = false)
    {
        static $connection = null;
        if ($connection instanceof PDO and !$overrideCached) {
            return $connection;
        }
        $params = array_merge(
            array(
                'hostname' => '127.0.0.1',
                'username' => get_current_user(),
                'password' => null
            ),
            $args
        );
        $params['host'] = $params['hostname'];
        $user = $params['username'];
        $pass = $params['password'];
        unset($params['hostname'], $params['username'], $params['password']);
        foreach ($params as $key => $val) {
            $params[$key] = sprintf('%s=%s', $key, $val);
        }
        $params = implode(';', $params);
        $connection = new PDO(sprintf('mysql:%s', $params), $user, $pass);
        return $connection;
    }
    
    function getLanguageFile($language)
    {
        return sprintf('%s/%s.php', LANGUAGES_DIRECTORY, $language);
    }
    
    function hasLanguageInDb(PDO $pdo, $language) {
        $stmt = $pdo->prepare(LANGUAGE_QUERY);
        $stmt->execute(array($language));
        return $stmt->fetchColumn() !== '0';
    }
    
    function includeLangFile($language)
    {
        if (!hasLanguageInDb(getDatabaseConnection(DB_SERVER), $language)) {
            return !trigger_error(DB_LANGUAGE_ERROR);
        }
        $filename = getLanguageFile($language);
        if (!file_exists($filename)) {
            return !trigger_error(FILE_LANGUAGE_ERROR);
        }
        require_once $filename;
    }
    
    getMysqlPdo(
        array(
            'hostname' => '127.0.0.1',
            'username' => 'root',
            'password' => 'root',
            'dbname' => 'teste',
            'charset' => 'UTF-8'
        )
    );
    includeLangFile(getCookieLanguage());

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pra você, o que são linhas de código? Indentar e espaçar um código-fonte não interfere em nada na performance, o parsing de caracteres ignorados é muitíssimo rápido. Para verificar alguma diferença de performance, você precisaria trocar cada quebra de linha do código em questão por, mais ou menos, 512mil quebras de linha (512k). Aí sim, vocẽ notaria uma pequena queda de performance. De fato, demanda mais recurso, uma vez que o tamanho em bytes do arquivo aumenta. Mas sem impacto na resposta final e com melhor aproveitamento/produtividade do programador.

 

Pra mim, as linhas de código são a parte escrita, sem os espaços e identação. Obrigado pelo esclarecimento, gosto de analisar tudo com números e ver como realmente funciona na prática. Gostaria de postar a "minha versão" do código para vcs darem uma analisada, mas sou tão burro que não entendi o que o autor do tópico precisa. :upset:

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Pra mim, as linhas de código são a parte escrita, sem os espaços e identação. Obrigado pelo esclarecimento, gosto de analisar tudo com números e ver como realmente funciona na prática. Gostaria de postar a "minha versão" do código para vcs darem uma analisada, mas sou tão burro que não entendi o que o autor do tópico precisa. :upset:

Quanto ao echo + exit, isso diminui a capacidade de reutilização das suas funções.

function soma() {
    echo array_sum(func_get_args());
}

soma(2, 2);
soma(1, 1);

Veja que eu não tenho como aproveitar esta função se eu precisar guardar esta soma em uma variável e utilizá-la mais pra frente, ou utilizar em conjunto com outras funções

var_dump(is_integer(soma(2, 2))); // false

Você deve se valer da palavra-chave return. Assim, será possível utilizar suas funções independente do contexto. Para imprimir, basta jogar o echo para fora da função

function soma() {
    return array_sum(func_get_args());
}

echo soma(1, 1);
echo soma(2, 2);

var_dump(is_integer(soma(3, 3))); //true

// Reutilizando a função soma:

function multiplica() {
    $numeros = func_get_args();
    $total = intval(array_shift($numeros));
    do {
        $multiplicador = intval(array_shift($numeros));
        $subtotal = 0;
        for ($i = 0; $i < $multiplicador; $i += 1) {
            $subtotal = soma($subtotal, $total);
        }
        $total = $subtotal;
    } while (is_integer(current($numeros)));
    return $total;
}

function potencia() {
    $numeros = func_get_args();
    $total = intval(array_shift($numeros));
    do {
        $potencia = intval(array_shift($numeros));
        $subtotal = 1;
        for ($i = 0; $i < $potencia; $i += 1) {
            $subtotal = multiplica($subtotal, $total);
        }
        $total = $subtotal;
    } while (is_integer(current($numeros)));
    return $total;
}

O mesmo vale para sair no primeiro erro.

 

Às vezes, quando uma mesma rotina pode falhar em múltiplos lugares, fica difícil descobrir a causa.

 

É por estes motivos que temos funções como mysql_error e preg_last_error.

 

Utilizando a excelente adaptação do @Enrico Pereira, fica fácil ficar alerta a erros e recuperá-los quando acontecerem.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.