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

Sign in to follow this  
Nazgulled

Problema com visibilidade em OOP, WTF?

Recommended Posts

Nazgulled

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?

Share this post


Link to post
Share on other sites
djthyrax

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


Não peças ajuda por PM! A tua dúvida vai ter menos atenção do que se for postada na secção correcta do fórum!

Share this post


Link to post
Share on other sites
shana

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


shana

Share this post


Link to post
Share on other sites
Nazgulled

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

Share this post


Link to post
Share on other sites
djthyrax

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

Não peças ajuda por PM! A tua dúvida vai ter menos atenção do que se for postada na secção correcta do fórum!

Share this post


Link to post
Share on other sites
shana

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:


shana

Share this post


Link to post
Share on other sites
Nazgulled

@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...

Share this post


Link to post
Share on other sites
MX+

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!

?>

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.