Publi

Conocer la accesibilidad de un método en PHP (público, privado, protegido)

Cuando programamos en PHP orientado a objetos, a veces, es importante conocer la visibilidad de ciertos métodos. Es una idea, que a priori puede resultar un poco ridícula, es decir, si llamo a un método es porque es público, si sólo lo puedo llamar desde las subclases, es porque es protegido, y si sólo lo puedo llamar desde la propia clase, es privado. Hasta aquí bien, pero… ¿y si colocamos un método intermediario? Es decir, siempre llamaremos al intermediario diciéndole el método que queremos llamar de esa misma clase. Puede que lo queramos hacer para mantener un log de las llamadas a los métodos de la clase, comprobar permisos de usuario, filtrar argumentos, etc; desde el mismo método de la clase, seguro que podemos llamar a todos los demás métodos, ya sean públicos, protegidos o privados, y tal vez ese comportamiento no nos interese, y sólo queremos que el método intermedio pueda llamar a los públicos.

Antes de meternos en el caso del ejemplo, vamos a ver una pequeña función, para comprobar la visibilidad del método:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
function methodType($class, $method)
{
  try
    {
      $method = new ReflectionMethod($class, $method);
     
      if ($method->isPrivate())
    return 'private';
      elseif ($method->isProtected())
    return 'protected';
      elseif ($method->isPublic())
    return 'public';
    }
  catch (Exception $e)
    {
      return 'error';
    }
}

class MyClass
{
  function __construct()
  {
  }

  private function myPrivate()
  {
    echo "shhh... this is private\n";
  }

  public function myPublic()
  {
    echo "Hello everybody!!\n";
  }

  protected function myProtected()
  {
    echo "Protected method!!\n";
  }

}

$myclass = new MyClass();

echo 'myPrivate: '.methodType($myclass, 'myPrivate')."\n";
echo 'myPublic: '.methodType($myclass, 'myPublic')."\n";
echo 'myProtected: '.methodType($myclass, 'myProtected')."\n";
echo 'notExists: '.methodType($myclass, 'notExists')."\n";
?>

Aquí tenemos la función methodType() a la cual le indicamos la clase y el método, y nos devolverá una cadena: (public, private, protected, error). Esta función hace uso de la clase ReflectionMethod de PHP, la cuál puede hacer muchas más cosas.

Ahora bien, volviendo al ejemplo del principio, a mí me gustaría guardar un registro de las llamadas a los métodos, por tanto, crearé una superclase MyClassBase que tendrá un método que utilizaré para llamar a los demás métodos, sólo si éstos son públicos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php
function methodType($class, $method)
{
  try
    {
      $method = new ReflectionMethod($class, $method);
     
      if ($method->isPrivate())
    return 'private';
      elseif ($method->isProtected())
    return 'protected';
      elseif ($method->isPublic())
    return 'public';
    }
  catch (Exception $e)
    {
      return 'error';
    }
}

class MyClassBase
{
  function __construct()
  {
    echo "Class created\n";
  }
 
  public function invoker($method, $arguments=array())
  {
  try
    {
      $method = new ReflectionMethod($this, $method);
     
      if ($method->isPublic())
    {
      echo "I'm invoking method ".$method->name."...\n";
      return $method->invokeArgs($this, $arguments);
    }
      else
    echo "Method ".$method->name." is not public!!\n";
    }
  catch (Exception $e)
    {
      echo "Error invoking ".$method."\n";
    }
  }
}

class MyClass extends MyClassBase
{
  function __construct()
  {
    echo "Creating MyClass...\n";
  }

  private function myPrivate()
  {
    echo "shhh... this is private\n";
  }

  public function myPublic()
  {
    echo "Hello everybody!!\n";
  }

  public function myPublicCalls()
  {
    echo "I'm a public method that calls private methods...\n";
    $this->myPrivate();
  }

  public function myPublicArguments($arg1, $arg2)
  {
    echo "I'm a public method with two arguments: ".$arg1." and ".$arg2."\n";
  }

  protected function myProtected()
  {
    echo "Protected method!!\n";
  }

}

$myclass = new MyClass();

$myclass->invoker('notExists');
$myclass->invoker('myPrivate');
$myclass->invoker('myPublic');
$myclass->invoker('myPublicCalls');
$myclass->invoker('myPublicArguments', array('argument1', 'argument2'));
?>

Cuya respuesta es:

Creating MyClass…
Error invoking notExists
Method myPrivate is not public!!
I’m invoking method myPublic…
Hello everybody!!
I’m invoking method myPublicCalls…
I’m a public method that calls private methods…
shhh… this is private
I’m invoking method myPublicArguments…
I’m a public method with two arguments: argument1 and argument2

De hecho, cuando se llama a un método privado o inexistente, invoker() se queja, es normal, PHP también lo haría, aunque podemos programar excepciones para que no se lance un error de PHP y hacerlo todo más bonito para el usuario final.
Cuando llamamos a un método público, podemos ejecutar código antes y después de la llamada, como decía (inicializaciones, logging, gestión de permisos, etc)
Un método público, por supuesto que puede ejecutar otros métodos privados, eso no ha cambiado y nunca cambiará.
Para pasar argumentos al método, debemos hacerlo desde un array, aunque si queremos hacerlo de la manera tradicional, hay un pequeño ejemplo aquí, en el punto 4.

También podría interesarte....

There are 2 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Pingback: Conversación de Programación. Build 2015.03 – Línea de Código /

Leave a Reply