• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Nazgulled

Problema com visibilidade em OOP, WTF?

9 mensagens neste tópico

Estava a preparar um exemplo para mostrar ao djthyrax a diferença entre private e protected e surgiu-me um problema que não consigo entender. Tudo no exemplo, funciona como diz nos comentários e acho que dá para perceber a diferença entre private/protected. Se estiver a dizer alguma asneira corrijam sff.

class A extends B {
protected function F1() {
	echo $this->B1; // Imposivel: $B1 = private em B
	echo $this->B2; // Possivel: $B2 = protected em B

	$this->F2(); // Possivel, F2() = private em A
}

private function F2() {
	echo "Estou em F2!";
}
}

class B {
private $B1;
protected $B2;

public function __construct() {
	$this->B1 = "xxx"; // Possivel: $B1 = private em B
	$this->B2 = "yyy"; // Possivel: $B2 = private em B

	$this->F1(); // Possivel: F1() = protected em A
	//$this->F2(); // Impossivel: F2() = private em A
}
}

$Teste = new A();

$Teste->B1 = '000'; // ***PROBLEMA***
$Teste->B2 = '000'; // Impossivel: B2 = protected em B

Como podem ver pelo comentário, a penúltima linha tem um problema... A variável B1 está declarada como private na classe B e a classe B será child da classe A (ou é parent? confundo sempre...). O problema é que aquela linha não provoca qualquer erro e de facto, a variável $B1, vai ter o valor '000'. Eu não percebo como isto é possível pois a variável é private e apenas deveria ser acedida dentro da classe. Correcto ou errado? A linha de baixo já dá erro, B2 é protected e tanto quanto eu saiba, private tem menos visibilidade que protected. Que me está a falhar?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Como estás a fazer extend, penso que a class que está a "expandir" sobrepõe-se à class mãe.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Como podem ver pelo comentário, a penúltima linha tem um problema... A variável B1 está declarada como private na classe B e a classe B será child da classe A (ou é parent? confundo sempre...).

Se declaras uma classe B, e depois dizes que A extende B, a A é filha de B (porque herda o que B tem)

O problema é que aquela linha não provoca qualquer erro e de facto, a variável $B1, vai ter o valor '000'. Eu não percebo como isto é possível pois a variável é private e apenas deveria ser acedida dentro da classe. Correcto ou errado?

Estes são os problemas de usar oop numa linguagem que não está preparada para isso de raíz...

O que está a acontecer é que B1 não existe em A, de todo. B1 existe em B, mas como é privado, A não faz ideia que B1 existe. Agora o pormenorzinho que mata a coisa é que o php, sendo uma linguagem que cria propriedades dinamicamente, olha para o $Teste->B1 e diz assim: "hmmm, o $Teste é do tipo A, mas o tipo A não tem nenhuma propriedade B1... eh, que se lixe, vou criar uma para o meu mestre ficar contente." E woosh, o objecto $Teste acabou de ganhar uma nova propriedade B1! E, claro, fica com o valor '000' que lhe é atribuído.

Esta nova propriedade B1 não é a mesma B1 do pai (porque o filho não faz a mais pequena ideia que o pai tem uma coisa dessas). Claro que toda a gente fica contente até ao dia em que alguém chegar ao pai e tornar a propriedade B1 protected em vez de private. Aí todo o código que mexa em B1 passa a fazer Boom.

Acho que este conceito de linguagens dinâmicas + oop se devia mesmo era chamar Oops...  :D

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas se A herda B, não deveria também herdar a variável B1? Herdou a B2, porque não herdar a B1? Ou só herda métodos/variáveis protected/public?

É estúpido maaaaannnnn! :D

Um dia, PHP vai ter OOP perfeito, vais ver :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas se A herda B, não deveria também herdar a variável B1? Herdou a B2, porque não herdar a B1?

Porque a B1 tem como valor NULL, ou seja, para o PHP é como se não tivesse sido definida. Experimenta fazer private $B1 = ''; uma vez que para o PHP null = indefinido, enquanto que string(0) = '' :D
0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas se A herda B, não deveria também herdar a variável B1? Herdou a B2, porque não herdar a B1? Ou só herda métodos/variáveis protected/public?

Não há realmente razão nenhuma para A herdar B1, visto que é totalmente proibido a A mexer em B1, ou ver sequer o conteúdo de B1. Até em termos de eficincia a construir os objectos de uma classe convém ser assim, porque se a linguagem tivesse de alocar tudo o que é público/protegido de B + tudo o de A + tudo o que é privado de B (que nunca vai ser acedido), os objectos ficariam consideravelmente maiores.

Essa parte eles fizeram muito bem, nada a apontar. Agora, claro, tendo uma linguagem que pode dinamicamente criar propriedades em objectos, e juntando à panela a optimização que faz com que os filhos não herdam campos privados dos pais, aí dá porcaria, como se vê :thumbsup:

É estúpido maaaaannnnn! :D

Hahahaha! Aaaah pois é! (/me lembra-se de uma certa thread onde se discutem as razões pelas quais o php é tão odiado...)

E o mais estúpido, é que o runtime podia verificar se os pais têm essas propriedades e lançar uma excepção... mas não. :P

*suspiro*

Um dia, PHP vai ter OOP perfeito, vais ver :D

Sim sim, e eu qualquer dia destes vou perder 10 quilos e ganhar uma viagem à volta do mundo com o brad pitt. :cheesygrin:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@djthyrax

Isso que tu dizes não tem lógica nenhuma e não adianta nada definir o conteúdo de $B1 na sua declaração. A $B2 também é null e no entanto o mesmo não acontece, e qual a razão disso?

Não há realmente razão nenhuma para A herdar B1, visto que é totalmente proibido a A mexer em B1, ou ver sequer o conteúdo de B1.

Esta! A qual eu agora entendo e concordo perfeitamente. E essa da excepção era um boa ideia... Eu acho a cena de criar dinamicamente propriedades porreira, mas concordo que algumas verificações deveriam ser feitas em situações como esta.

Quanto ao "odio" do PHP e apesar do meu insulto ao mesmo, eu gosto de PHP e não vou entrar noutra discussão como noutro tópico. Eu gosto de PHP e não me vejo a mudar para outra linguagem para fazer páginas dinâmicas. Já programo em PHP há uns anos e não tenho razão nenhuma para mudar.

Perderes 10quilos não custa nada, apenas força de vontade lol... E a volta ao mundo, quanto a ti, não sei, mas eu vou ganhar a que a Super Bock está a sortear, só não vai ser com o Brad Pitt, mas também não quero saber dele para nada. Eu acredito que o PHP daqui a uns anos (nunca disse que ia ser amanhã), possa ter uma implementação melhor de OOP com todos esses pormenores limados. Mas é provável que seja algo que ainda demore o seu tempo...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Posso dizer que resolvi o problema =D

Basicamente fazemos overload da função A, e prevenimos a escrita e leitura, prevenimos erros e podemos logar possíveis erros até.. o que quiserem.

A função ImprimeB1() serve para demonstrar que no final do script, a variável private B1 é mantida, e que não foi criada dinamicamente em A. Cumprimentos.

EDIT: Adicionei a função ImprimeB1_A para confirmar que não existe B1 em A.

<?php

error_reporting(E_ALL);
function P($s){echo "$s<br />";}

class A extends B {

function __set($var,$value) {

	if ( @$this->{$var} ) {
		P("Escrita: $var Acessivel");
	}
	else
	{
		P("Escrita: $var Bloqueada");
	}
}

function __get($var) {

	if ( @$this->{$var} ) {
		P("Leitura: $var Acessivel");
	}
	else
	{
		P("Leitura: $var bloqueada");
	}
}

protected function F1() {
	P($this->B1); // Notice: $B1 = private em B
	P($this->B2); // OK!: $B2 = protected em B

	$this->F2(); // OK: F2() = private em A
}

private function F2() {
	P("Estou em F2!");
}

public function ImprimeB1_A()
{
	P($this->B1);
}
}

class B {

private $B1;
protected $B2;

public function __construct() {
	P("<b>Class B Loaded!</b>");

	$this->B1 = "xxx"; // OK: $B1 = private em B
	$this->B2 = "yyy"; // OK: $B2 = private em B

	$this->F1(); // OK: F1() = protected em A
	#$this->F2(); // Fatal: F2() = private em A
}

public function ImprimeB1() {
	P($this->B1);
}
}

$Teste = new A();

P("<b>Class A Loaded!</b>");

$Teste->B1 = '000'; // NOT: Testar a escrita ..

P($Teste->B1); // NOT: B1 = privada em B, nem vai ser criada dinamicamente.

$Teste->ImprimeB1(); // OK: Imprime o resultado esperado, só existe um B1 e encontra-se em B. 
$Teste->ImprimeB1_A(); // Confirmar que não existe variável B1 em A!

?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora