Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
no exemplo abaixo eu consigo obter o valor de $foo-> testando
não deveria poder, ja que é private
algo de errado?
$_foo = new Foo;
$foo-> teste();
print_r( $foo-> testando );
class Foo
{
/*
**
*/
private $testando = array();
}
/*
**
*/
class Bar extends Foo
{
/*
**
*/
public function teste()
{
/*
**
*/
$this-> testando = 'opa';
}
}... na verdade errei quando escrevi aqui
o correto é a instancia de bar
$_bar = new Bar;
$bar-> teste();
print_r( $bar-> testando );
private $_testando continua como private e sendo exibido
o exemplo que você deu apenas muda a saida pq você refez a array
se refizer sem extends, $_testando passa a nao ser acessado:
/*
**
*/
class Bar
{
/*
**
*/
private $_testando = array('privado');
/*
**
*/
public function teste()
{
/*
**
*/
$this->_testando[] = 'opa';
}
}Pois é, como você está na mesma classe, o PHP consegue validar a regra de visibilidade da variável. Como no caso inicial trata-se de uma classe extendida, o PHP não tem a visibilidade a variável da classe Pai, desta forma, o próprio PHP entende que você está setando uma variável nova quando você faz a declaração que a variável $_testando recebe um novo valor. Para evitar esses tipos de problemas, como boa regra na programação, vale a pena você criar protected métodos __set , __get e também criar um para mostrar a variável.
Exemplo:
$bar = new Bar;
$bar->teste();
echo '<br />';
$bar->mostrar_testando();
class Foo
{
private $_testando = array('privado');
protected function __set($name, $value) {
echo "Setando '$name' para '$value'\n";
$this->_testando[$name] = $value;
}
protected function __get($name) {
echo "Obtendo '$name'\n";
if (array_key_exists($name, $this->_testando)) {
return $this->_testando[$name];
}
$trace = debug_backtrace();
trigger_error(
'Propriedade não definida via __get(): ' . $name .
' em ' . $trace[0]['file'] .
' na linha ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
public function mostrar_testando(){
print_r( $this->_testando );
}
}
class Bar extends Foo
{
public function teste()
{
$this->_testando = 'opa';
}
}
Acho que assim tudo funcionaria como o esperado. Me confirme se era isso que você queria.
Você só consegue acessar um atributo private dentro da própria classe,impossível acessá-lo fora.
Dependendo do que queres fazer, faça enpasulamento deste atributo, e o chame de public, que então poderá chamá-lo em qualquer classe.
Provavelmente seus alertas de erro estão muito baixos ou desativados pois do jeito que você demonstrou no post #3 geraria o seguinte erro:
Notice: Undefined variable: bar...
E
Fatal error: Call to a member function teste() on a non-object...
E mesmo se consertasse trocando $_bar por $bar, teria esse outro:
Notice: Undefined property: Bar::$testando
E se consertasse trocando o testando por _testando, finalmente teria:
Fatal error: Cannot access private property Bar::$_testando...
Lembre-se de sempre que estiver desenvolvendo, iniciar o script com:
ini_set( 'display_errors', TRUE );
error_reporting( E_ALL | E_STRICT );>
Acho que assim tudo funcionaria como o esperado. Me confirme se era isso que você queria.
na verdade não quero 'arrumar' outra forma de fazer, o problema é um atributo privado sendo acessado fora da classe
Bruno,
quando estou desenvolvendo defino o seguinte:
date_default_timezone_set ( 'America/Sao_Paulo' );
ini_set ( 'display_errors' , true );
error_reporting ( E_ALL | E_STRICT );
ini_set ( 'default_charset', 'UTF-8' );
acontece que não ha alerta nenhum, de nenhum tipo
ignore o erro de digitação :)
o exemplo dando erro ainda, a saida é a seguinte:
$_bar = new Bar;
$_bar-> teste();
print_r( $_bar);
class Foo
{
private $testando = array();
}
class Bar extends Foo
{
public function teste()
{
$this-> testando = 'opa';
}
}
Bar Object
(
[testando:Foo:private] => Array
(
)
[testando] => opa
)Você apenas está estranhando o retorno obtido, mas está certo.
Quando você declara:
class Foo {
private $testando = array();
}
Você define explícitamente que todo e qualquer objeto de Foo poderá usar, dentro de seu contexto, a propriedade testando, que é um array.
Quando você faz:
class Bar extends Foo {
public function teste() {
$this -> testando = 'opa';
}
}
Você define que quando Bar::teste() for invocado, a propriedade testando, visivelmente presente na classe-pai terá o valor opa.
Mas veja a visibilidade da propriedade testando. Ela é private, ou seja, de acessibilidade restrita única e exclusivamente no contexto de Foo. Bar JAMAIS terá acesso à ela.
Mas e por quê funciona?
Simples. Porque como você não definiu uma propriedade chamada testando em Bar e a existente em Foo é particular (já que privada é feio :P ), o interpretador precisa obedecer sua vontade com a string opa então ele cria uma propriedade em runtime.
E por omissão de visibilidade, public é internamente atribuído.
Mas não deveria haver um conflito de nomes?
Na minha opinião, isso deveria de fato acontecer, mas verdade não acontece. O motivo também é simples: hierarquia de visibilidade (inventei isso agora):
Nessa hierarquia tem-se:
|- private
|- protected
|- public
Isso significa que public é a visibilidade mais fraca de todas. Mas não se engane, aqui o jogo rola ao contrário. A visibilidade mais fraca supera a mais forte (private).
É a mesma coisa que um quatro de paus no Jogo de Truco. É a carta mais fraca do jogo, mas se vira o três, ela se transforma no todo poderoso gato (ou zap, se estiver em São Paulo).
Mas como assim?
Faça os testes e veja o interpretador reclamando:
Fatal error: Access level to Bar::$testando must be public (as in class Foo)
Entendeu?
O código para funcionar de forma adequada e esperada deveria ter Foo::testando como protected e, se necessário, um Foo::getTestando(), para que você resgate o valor a nível de instância.
Por ser protected, quando Bar::teste() tenta modificar uma propriedade que ela desconhece, vai procurar na classe pai e por encontrar E puder enxergar, vai modificá-la sem criar outra em tempo de execução.
medalha de ouro :)
isso observei no #3, mas como fiquei no 'achismo', optei por uma resposta mais coerente
então ele está criando a propriedade na class Bar, é isso?
Isso, isso, isso, isso, isso, isso, isso, isso... ^_^
Bem que seria interessante que ele mudassem isso. Tem muita coisa no PHP que é automatica que não deveria ser pra não acabar confundindo.
então se eu usar metodo publico a classe Bar vai poder usar a propriedade de Foo
não acho que seja necessário um getter para o propósito, é apenas um controle extends para eu poder acessar algumas propriedades diretamente na execução: executa, processa e acessa
concordo que deveria mudar isso :)
mas como nada é perfeito...
Não, se você não precisa de um getter para que possa usar o valor fora da classe, isto é, a nível da instância, como ecoá-la, por exemplo, então protected resolve.
E temos mais uma vez aqui ilustrado um dos aspectos meio incompreensíveis do PHP.
Eu já tinha observado o que o Bruno Augusto falou no post #8, mas não postei pois estou meio corrido aqui com o final do semestre na faculdade.
De fato, o PHP gosta de 'assumir' coisas. Se você tenta utilizar uma constante não definida, ele 'assume' que é uma string. Se você tenta acessar uma propriedade inexistente, ele tenta criá-la.
Quem sabe o PHP6 resolva essas questões, que acabam realmente confundindo.
vou testar com protected
obrigadão Bruno
resolvido :)
valeu Henrique
vou procurar mais sobre essas capengadadas do PHP pra evitar surpresa
Teu Código está errado, deveria ser:
class Foo
{
/*
**
*/
/*
**
*/
class Bar extends Foo
{
/*
**
*/
O PHP cria duas variáveis $testando uma é privada com valor = array () e uma outra que é pública com valor = opa.
Você pode verificar que se você alterar o código para esse abaixo, você não tem mais acesso a variável private criada na classe pai.
class Foo
{
/*
**
*/
/*
**
*/
class Bar extends Foo
{
/*
**
*/
Se fosse a mesma variável, deveria resultar em:
Array ( [0] => privado [1] => opa )
e não:
Array ( [0] => opa )
Entendeu?