Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Galera,
Em minhas funções costumo usar arrays associativos que contém os parâmetros das funções utilizadas nas classes.
Por exemplo:
$params = [
'action' => 1,
'nome' => '$nome',
'sobrenome' => '$sobrenome' ];
$obj = new User;
$obj->runUserAction($params);
O método runUserAction da classe User chama várias outros métodos de validação e sanitização internas da classe e tals e depois, se tiver tudo ok, grava no banco (se for action === 1) ou atualiza o banco (action === 2), etc. Fiz um if/ifelse/else pra isso.
Minhas dúvidas são:
1) Estou criando o array de parâmetro no controller, que envia pra classe. É isso?
2) Arrays associativos são boas formas de enviar esses parâmetros?
3) Do ponto de vista funcional, utilizar esse parâmetro "action" tem sido uma mão na roda e funciona perfeitamente. Continuo ou crio um método exclusivo para cada operação?
Abraços e muito obrigado!!!
Aff... é aquela coisa de noob na programação OO. Ainda meio que "traduzo" as coisas da estruturada pra orientada.
Sobre o SoC, sempre tive uma dificuldade pra entender se é pra "classe" ou pro "método".
Pra classe, é meio obvio, claro: a classe Usuário trata sobre assuntos de Usuário (e não de Items, por exemplo) e cada método realiza uma função exclusiva (que eu sei que deveria ter feito assim, mas fiz a runUserAction, que encapsula o CRUD). No entanto, os demais parecem estar corretos.
Já sentia que tava fazerndo besteira hehehe, por isso a bsuca por conselhos.
Mas ainda não sei o pq do problema com os arrays. Eles (mais uma vez falando da minha experiência) apareceram como a melhor forma pra resolver um outro problema. Uma planilha com 8 colunas x 40 linhas ou mais. Antigamente, na procedural, eu usava um while e um loop e mandava bala linha por linha. Agora, escrevo tudo num array associativo multidimensional no controller e envio pra validação/sanitização na classe.
Muito obrigado pela ajuda W.B.
Uma matriz bidimensional é uma tabela. Por isso a solução com um array de arrays foi clara e precisa para representar o conteúdo de uma planilha.
Agora, hash tables não são a melhor forma de representar os parâmetros de uma função.
Primeiro porque hash tables são livres. Quando a sua função espera um array para operar os itens deste array ao invés de operar o todo, você não possui garantia que receberá os dados corretos.
Pelo bem da sua própria sanidade mental, o código deve ser verboso e autoexplicativo ao máximo
function obterQuociente($dividendo, $divisor)
{
return $dividendo / $divisor;
}function obterQuociente($componentes_da_divisao)
{
if (!in_array('dividendo', $componentes_da_divisao)) {
trigger_error('informe o dividendo!');
return;
}
if (!in_array('divisor', $componentes_da_divisao)) {
trigger_error('informe o divisor!');
return;
}
return $componentes_da_divisao['dividendo'] / $componentes_da_divisao['divisor'];
}Got It!
Valeu. Estou compreendendo td até o momento, mas vou continuar com as perguntas, ok? hehehe
No exemplo que vc postou aparecem 2 parâmetros. Beleza.
Mas supondo que eu tenha uma classe Cadastro, e suas respectivas funções de validação, select, insert, remove, etc....
Eu poderia separar o envio em arrays diferentes, com cada conjunto de funções ou funções agindo sobre cada array.
Por exemplo:
$userFullName = [
'nome' => $nome,
'sobrenome' => $sobrenome ];
$userFullAdress = [
'rua' => $rua,
'numero' =>$numero,
'bairro' => $bairro,
'cidade' => $cidade,
'uf '=> $uf ];
$userContact = [
'email' => $email,
'telefone1' => $telefone1,
'telefone2' => $telefone2 ];
$obj = new Cadastro;
$obj->_insertThat($userFullName, $userFullAdress, $userContact);
O que to querendo dizer é que isso me pareceu (to engatinhando ainda) mais manuseável e prático do que fazer:
$obj = new Cadastro;
$obj->_insertThat($nome, $sobrenome, $rua, $numero, $bairro, $cidade, $uf, $email, $telefoen1, $telefone2);
A não ser que tenha uma forma melhor de passar os parâmetros que eu não tenha captado =D
Valeu!!!
Outra coisa que percebi agora após reler o teu comentário, é que eu não estou validando os dados dentro do array.
Dentro do método eu tenho feito algo como
$name = this->validateAndSanitizeNames($userFullName['nome']);
$familyname = this->validateAndSanitizeNames($userFullName['sobrenome']);
=P e agora?
>
Got It!
Valeu. Estou compreendendo td até o momento, mas vou continuar com as perguntas, ok?
OK
>
No exemplo que vc postou aparecem 2 parâmetros. Beleza.
Mas supondo que eu tenha uma classe Cadastro, e suas respectivas funções de validação, select, insert, remove, etc....
Eu poderia separar o envio em arrays diferentes, com cada conjunto de funções ou funções agindo sobre cada array.
Por exemplo:
$userFullName = [
'nome' => $nome,
'sobrenome' => $sobrenome ];
$userFullAdress = [
'rua' => $rua,
'numero' =>$numero,
'bairro' => $bairro,
'cidade' => $cidade,
'uf '=> $uf ];
$userContact = [
'email' => $email,
'telefone1' => $telefone1,
'telefone2' => $telefone2 ];
$obj = new Cadastro;
$obj->_insertThat($userFullName, $userFullAdress, $userContact);
Renomeia essa classe pra Usuário, pelo amor de Deus!
>
O que to querendo dizer é que isso me pareceu (to engatinhando ainda) mais manuseável e prático do que fazer:
$obj = new Cadastro;
$obj->_insertThat($nome, $sobrenome, $rua, $numero, $bairro, $cidade, $uf, $email, $telefoen1, $telefone2); A não ser que tenha uma forma melhor de passar os parâmetros que eu não tenha captado =D
Valeu!!!
Que tal...
class User
{
private $name;
private $surname;
private $address;
private $contatc;
}
class UserAddress
{
private $addressName;
private $number;
private $district;
private $city;
private $state;
}
class UserContact
{
private $email;
private $primaryPhone;
private $optionalPhone;
}
>
Outra coisa que percebi agora após reler o teu comentário, é que eu não estou validando os dados dentro do array.
Dentro do método eu tenho feito algo como
$name = this->validateAndSanitizeNames($userFullName['nome']);
$familyname = this->validateAndSanitizeNames($userFullName['sobrenome']);
=P e agora?
E agora que se você recebe uma hash table que não tenha as chaves nome ou sobrenome, você tem um erro que será difícil de rastrear.
Aff... aquela classe Cadastro é hipotética hehehe não estou usando meu código, apenas exemplos pra ilustrar minhas dúvidas.
Só mais uma questãozinha hehehe: no caso de usar classes diferentes para manusear os dados do cadastro, usaria tabelas diferentes no banco de dados?
>
Aff... aquela classe Cadastro é hipotética hehehe não estou usando meu código, apenas exemplos pra ilustrar minhas dúvidas.
Só mais uma questãozinha hehehe: no caso de usar classes diferentes para manusear os dados do cadastro, usaria tabelas diferentes no banco de dados?
Há casos e casos. Nem sempre uma classe significa uma tabela. O ideal é agrupar por assunto e, principalmente, por responsabilidade.
Substituir muitos argumentos de uma função / método por um array de parâmetros não é de todo errado. Se assim o fosse, não seria uma idéia aprovável para versões futuras do PHP (vide argument unpacking do PHP 5.6).
E nem adianta dizer que não é porque é uma feature vai ser implementada que ela é uma boa prática.
Gera complexidade ciclomática? Gera. Mas mais em funções ou métodos estáticos do que numa classe bem formada propriamente dita.
E foi justamente visando minimizar esse problema eu criei um módulo Parameter como parte do meu monstrinho que trabalha em conjunto com uma interface que define que um determinado objeto será parametrizável.
É tudo muito simples. Uma classe que possa ter seu comportamento modificado através de vários parâmetros assina a interface e disponibiliza dois métodos, um para setar as opções e um para resgatá-las.
Isso já se evita aquelas classes com vários getters / setters. :thumbsup:
O objeto só exige um argumento como requerido, que são as opções que o formarão, mas aceita até três. As opções iniciais podem ser diretamente os valores de uma model depois de tratados, por exemplo, como pode ser algo mais.
Num cenário mais completo as opções iniciais podem ser a opções-padrão da classe, aquelas que são assumidas caso ausentes no segundo ou terceiro parâmetros:
XML\Writer
class Writer extends \XMLWriter implements Parameterizable {
/**
* XML Writer Default Options
*
* @var array $defaultOptions
*/
private $defaultOptions = array(
'addPrologue' => TRUE,
'version' => '1.0',
'charset' => 'utf-8',
'indent' => array(
'enabled' => TRUE,
'char' => "\t",
'repeat' => 1
),
);
// ...
}
Essa classe é um wrapper para XmlWriterque eu fiz Isso e nela as opções-padrão definem as características do XML final. Por exemplo, por padrão o XML será indentado por uma tabulação, mas se criássemos esse objeto assim:
$xml = new XML\Writer(
array( 'indent' => array( 'char' => ' ', 'repeat' => 4 ) )
);
Teríamos um XML indentado por quatro espaços. :o <_< :lol:
Isso já garante redução de complexidade ciclomática pois dispensa-se verificações pela existência das entradas. :thumbsup:
O segundo argumento pode ser as opções-filhas ou as opções de usuário, dependendo se o terceiro argumento foi informado ou não.
Opções-filhas cabem no contexto de abstração e, consequentemente, herança.
Para que as classes filhas não tenham de sobrescrever o construtor da classe-pai, desperdiçando performance sem motivos (já que objetos não podem ser definidos fora de um método de classe), a classe-pai cria o objeto Parameter numa propriedade protegida, (garantindo acesso pelas classes-filhas) e usa, como segundo argumento, o método Parameterizable::setOptions() que toda classe parametrizável deve implementar:
Cache\Backend\AbstractBackend
abstract class AbstractBackend implements Parameterizable {
// ...
/**
* Backend Default Common Options
*
* @var array $defaultOptions
*/
private $defaultOptions = array(
'lifeTime' => 86164, // One sideral day (rounded): 23h 56m 4.09s
);
protected $options;
public function __construct( $options = NULL ) {
$this -> options = new Parameter(
$this -> defaultOptions, $this -> setOptions(), $options
);
}
}
Cache\Backend\File
class File extends Cache\Backend\AbstractBackend {
// ...
public function setOptions() {
return array(
'outputDirectory' => 'Cache'
);
}
// ...
}
As classes filhas implementam o método de interface e definem opções que podem sobrescrever entradas da classe-pai ou criar novas, de acordo com suas necessidades.
Esses são dois fragmentos de classes de caching por arquivos.
Criando-se esse objeto sem modificá-lo, teremos os arquivos de cache num diretório /Cache a partir da raiz da aplicação os quais teriam validade de um dia.
Mas se fizéssemos:
$backend = new Cache\Backend\File(
array( 'lifetime' => 3600 )
);
Teríamos um cache que duraria apenas uma hora. :o <_< :lol:
Por fim, se informados todos os três argumentos de Parameter, as opções do usuário que modificam aquilo que foi pré-definido pelas classes são, normalmente, definidos pelo construtor do objeto e também são opcionais.
No mesmo exemplo acima, criando o mesmo objeto dessa forma:
$backend = new Cache\Backend\File(
array( 'outputDirectory' => 'Data/Cache' )
);
Teríamos o diretório dos arquivos de caching um nível mais adentro da hierarquia. :o <_< :lol:
A integridade das opções, por sua vez, fica isolada num método à parte, normalmente invocado depois de objeto final estar formado com todas as opções:
class File extends Cache\Backend\AbstractBackend {
// ...
protected function checkIntegrity() {
// ...
$info = new \SplFileInfo( $dir );
if( ! $info -> isDir() ) {
throw new Exception(
sprintf(
'Output Cache Directory <strong>%s</strong> doesn\'t exists',
$dir
)
);
}
}
// ...
}
É perfeito? Claro que não. Mas pelo menos resolve um problema de forma completa, sem gambiarras e com uma carga relativamente pequena.Concordo 100% com o @Bruno Augusto , a própria Zend em seu Framework utiliza array em seus models para popular um objeto com seus métodos setOptions($options = null);
NOTA: Também criei uma classe de Entidade Abstrata e um Mapper para remover estes inúmeros getters e setters :D
Eae,
Eu acho o seguinte cara:
bad smell
Leia sobre SOC e SRP
não, até pq o seu método está com muitas responsabilidades
crie um método para cada operação. Ou até melhor, utilize REST, e use um roteamento e um VERBO http para cada operação.