PHP Orientado a Objetos
La orientación a objetos (Object-Oriented, abreviado OO) es una idea y método de programación que encapsula los datos del programa y los métodos para operar con ellos en "objetos", y completa las funciones del programa mediante la interacción y el paso de mensajes entre objetos. La programación orientada a objetos enfatiza características como encapsulación, herencia, polimorfismo y enlace dinámico, lo que proporciona al programa una mejor extensibilidad, mantenibilidad y reutilización.
En la programación orientada a objetos (en inglés: Object-oriented programming, abreviado OOP), un objeto es un todo compuesto por información y descripciones del procesamiento de esa información, y es una abstracción del mundo real.
En el mundo real, todo lo que enfrentamos son objetos, como computadoras, televisores, bicicletas, etc.
Las tres características principales de los objetos:
- Comportamiento del objeto: las operaciones que el objeto puede realizar, por ejemplo: encender la luz, apagar la luz son comportamientos.
- Estado del objeto: cómo responde el objeto a diferentes comportamientos, por ejemplo: color, tamaño, apariencia.
- Representación del objeto: la representación del objeto es equivalente a una identificación, y distingue específicamente en qué se diferencian los mismos comportamientos y estados.
Por ejemplo, Animal es una clase abstracta; podemos concretar en un perro y una oveja. El perro y la oveja son objetos concretos; tienen atributos como el color, y comportamientos como caminar, correr, etc.

Las tres características principales de la programación orientada a objetos:
Encapsulación: se refiere a encapsular juntas las propiedades y métodos del objeto, de modo que el exterior no pueda acceder ni modificar directamente el estado interno del objeto. Mediante el uso de modificadores de control de acceso (public, private, protected) se restringen los permisos de acceso de propiedades y métodos, logrando así la encapsulación.
Herencia: se refiere a que se puede crear una nueva clase que herede las propiedades y métodos de la clase padre, y además puede añadir sus propias propiedades y métodos. Mediante la herencia, se puede evitar escribir código similar de forma repetida y se puede lograr la reutilización del código.
Polimorfismo: se refiere a que se puede usar una variable de tipo clase padre para referenciar objetos de diferentes tipos de subclases, logrando así operaciones unificadas sobre diferentes objetos. El polimorfismo hace que el código sea más flexible, con mejor extensibilidad y mantenibilidad. En PHP, el polimorfismo se puede lograr mediante la implementación de interfaces y el uso de clases abstractas.
Contenido de orientación a objetos
Clase− Define las características abstractas de una cosa. La definición de la clase incluye la forma de los datos y las operaciones sobre los datos.
Objeto− Es una instancia de la clase.
Variable miembro− Variable definida dentro de la clase. Su valor no es visible desde el exterior, pero se puede acceder a través de las funciones miembro; una vez que la clase se instancia como objeto, esta variable se convierte en una propiedad del objeto.
Función miembro− Se define dentro de la clase y se puede utilizar para acceder a los datos del objeto.
Herencia− La herencia es un mecanismo por el cual una subclase comparte automáticamente la estructura de datos y los métodos de la clase padre; es una relación entre clases. Al definir e implementar una clase, se puede hacer sobre la base de una clase ya existente, tomando el contenido definido por esa clase existente como contenido propio y añadiendo varios contenidos nuevos.
Clase padre− Si una clase es heredada por otras clases, se la puede llamar clase padre, clase base o superclase.
Subclase− Una clase que hereda de otras clases se llama subclase, y también se puede llamar clase derivada.
Polimorfismo− El polimorfismo se refiere a que la misma función o método puede actuar sobre objetos de varios tipos y obtener diferentes resultados. Si diferentes objetos, al recibir el mismo mensaje, producen diferentes resultados, este fenómeno se denomina polimorfismo.
Sobrecarga− En pocas palabras, es la situación en la que funciones o métodos tienen el mismo nombre pero listas de parámetros diferentes. Estas funciones o métodos con el mismo nombre pero diferentes parámetros se denominan mutuamente funciones o métodos sobrecargados.
Abstracción− La abstracción se refiere a abstraer objetos que tienen una estructura de datos (atributos) y comportamientos (operaciones) consistentes en una clase. Una clase es una abstracción de este tipo; refleja las propiedades importantes relacionadas con la aplicación e ignora otros contenidos irrelevantes. Cualquier división de clases es subjetiva, pero debe estar relacionada con la aplicación específica.
Encapsulación− La encapsulación se refiere a vincular los atributos y comportamientos de un determinado objeto del mundo real y colocarlos en una unidad lógica.
Constructor− Se utiliza principalmente para inicializar el objeto al crearlo, es decir, asignar valores iniciales a las variables miembro del objeto; siempre se usa junto con el operador new en la declaración de creación del objeto.
Destructor− El destructor es lo opuesto al constructor. Cuando el objeto termina su ciclo de vida (por ejemplo, cuando la función donde se encuentra el objeto ha terminado de ejecutarse), el sistema ejecuta automáticamente el destructor. El destructor se utiliza a menudo para hacer el trabajo de "limpieza posterior" (por ejemplo, si al crear el objeto se asignó un espacio de memoria con new, se debe liberar con delete en el destructor antes de salir).
En la siguiente figura, creamos tres objetos mediante la clase Car: Mercedes, Bmw y Audi.
$mercedes = new Car (); $bmw = new Car (); $audi = new Car ();

Definición de clases en PHP
La sintaxis habitual para definir una clase en PHP es la siguiente:
<?php
class phpClass {
var $var1;
var $var2 = "constant string";
function myfunc ($arg1, $arg2) {
[..]
}
[..]
}
?>
El análisis es el siguiente:
Una clase se define usandoclassla palabra clave seguida del nombre de la clase.
Dentro del par de llaves ({}) después del nombre de la clase se pueden definir variables y métodos.
Las variables de la clase se declaran usandovarpara declararlas; las variables también pueden inicializarse con valores.
La definición de funciones es similar a la definición de funciones de PHP, pero las funciones solo se pueden acceder a través de la clase y de los objetos instanciados a partir de ella.
Ejemplo
<?php
class Site {
/* 成员变量 */
var $url;
var $title;
/* 成员函数 */
function setUrl($par){
$this->url = $par;
}
function getUrl(){
echo $this->url . PHP_EOL;
}
function setTitle($par){
$this->title = $par;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
?>
Variable$thisrepresenta el objeto en sí mismo.
PHP_EOLEs el salto de línea.
Creación de objetos en PHP
Después de crear la clase, podemos usarnewel operador para instanciar objetos de esa clase:
$ejemplo = new Site; $taobao = new Site; $google = new Site;
En el código anterior creamos tres objetos, cada uno de ellos independiente. A continuación, veamos cómo acceder a las funciones miembro y variables miembro.
Llamar a métodos miembro
Después de instanciar el objeto, podemos usar ese objeto para llamar a los métodos miembro; los métodos miembro de ese objeto solo pueden operar sobre las variables miembro de ese objeto:
// 调用成员函数,设置标题和URL $ejemplo->setTitle( "Ejemplo" ); $taobao->setTitle( "淘宝" ); $google->setTitle( "Google 搜索" ); $ejemplo->setUrl( 'www.example.com' ); $taobao->setUrl( 'www.taobao.com' ); $google->setUrl( 'www.google.com' ); // 调用成员函数,获取标题和URL $ejemplo->getTitle(); $taobao->getTitle(); $google->getTitle(); $ejemplo->getUrl(); $taobao->getUrl(); $google->getUrl();
El código completo es el siguiente:
Ejemplo
class Site {
/* Variables miembro */
var $url;
var $title;
/* Funciones miembro */
function setUrl($par){
$this->url = $par;
}
function getUrl(){
echo $this->url . PHP_EOL;
}
function setTitle($par){
$this->title = $par;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
$ejemplo = new Site;
$taobao = new Site;
$google = new Site;
// Llamar a las funciones miembro para configurar el título y la URL
$ejemplo->setTitle( Tutorial Ejemplo);
$taobao->setTitle( Taobao);
$google->setTitle( Búsqueda de Google);
$ejemplo->setUrl( 'www.example.com' );
$taobao->setUrl( 'www.taobao.com' );
$google->setUrl( 'www.google.com' );
// Llamar a las funciones miembro para obtener el título y la URL
$ejemplo->getTitle();
$taobao->getTitle();
$google->getTitle();
$ejemplo->getUrl();
$taobao->getUrl();
$google->getUrl();
?>
Ejecutar ejemplo »
Al ejecutar el código anterior, el resultado es:
Ejemplo 淘宝 Google 搜索 www.example.com www.taobao.com www.google.com
Constructor de PHP
El constructor es un método especial. Se utiliza principalmente para inicializar el objeto al crearlo, es decir, para asignar valores iniciales a las variables miembro del objeto. En la declaración de creación del objeto se usa junto connewel operador.
PHP 5 permite a los desarrolladores definir un método en una clase como constructor. El formato de sintaxis es el siguiente:
void __construct ([ mixed $args [, $... ]] )
En el ejemplo anterior podemos inicializar las variables $url y $title mediante el método constructor:
function __construct( $par1, $par2 ) {
$this->url = $par1;
$this->title = $par2;
}
Ahora ya no necesitamos llamar a los métodos setTitle y setUrl:
Ejemplo
$taobao = new Site('www.taobao.com', 'Taobao');
$google = new Site('www.google.com', 'Búsqueda de Google');
// Llamar a las funciones miembro para obtener el título y la URL
$ejemplo->getTitle();
$taobao->getTitle();
$google->getTitle();
$ejemplo->getUrl();
$taobao->getUrl();
$google->getUrl();
Ejecutar ejemplo »
Destructor
El destructor es lo opuesto al constructor. Cuando el objeto termina su ciclo de vida (por ejemplo, cuando la función donde se encuentra el objeto ha terminado de ejecutarse), el sistema ejecuta automáticamente el destructor.
PHP 5 introdujo el concepto de destructor, similar a otros lenguajes orientados a objetos. Su formato de sintaxis es el siguiente:
void __destruct ( void )
Ejemplo
<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "销毁 " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
Al ejecutar el código anterior, el resultado es:
构造函数 销毁 MyDestructableClass
Herencia
PHP usa la palabra claveextendspara heredar una clase. PHP no admite herencia múltiple, el formato es el siguiente:
class Child extends Parent {
// 代码部分
}
Ejemplo
En el ejemplo, la clase Child_Site hereda de la clase Site y amplía su funcionalidad:
<?php
// 子类扩展站点类别
class Child_Site extends Site {
var $category;
function setCate($par){
$this->category = $par;
}
function getCate(){
echo $this->category . PHP_EOL;
}
}
Anulación de métodos
Si los métodos heredados de la clase padre no satisfacen las necesidades de la clase hija, se pueden reescribir. Este proceso se llama anulación (override) de métodos, también conocido como sobrescritura de métodos.
En el ejemplo se anulan los métodos getUrl y getTitle:
function getUrl() {
echo $this->url . PHP_EOL;
return $this->url;
}
function getTitle(){
echo $this->title . PHP_EOL;
return $this->title;
}
Control de acceso
El control de acceso a propiedades o métodos en PHP se implementa agregando delante la palabra clave public (público), protected (protegido) o private (privado).
- public (público):Los miembros de clase públicos pueden ser accedidos desde cualquier lugar.
- protected (protegido):Los miembros de clase protegidos pueden ser accedidos por la propia clase, así como por sus subclases y su clase padre.
- private (privado):Los miembros de clase privados solo pueden ser accedidos por la clase en la que se definen.
Control de acceso a propiedades
Las propiedades de una clase deben definirse como una de: pública, protegida o privada. Si se definen con var, se consideran públicas.
<?php
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// 可以对 public 和 protected 进行重定义,但 private 而不能
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // 这行能被正常执行
echo $obj2->private; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>
Control de acceso a métodos
Los métodos de una clase pueden definirse como públicos, privados o protegidos. Si no se establecen estas palabras clave, el método es público por defecto.
<?php
/**
* Define MyClass
*/
class MyClass
{
// 声明一个公有的构造函数
public function __construct() { }
// 声明一个公有的方法
public function MyPublic() { }
// 声明一个受保护的方法
protected function MyProtected() { }
// 声明一个私有的方法
private function MyPrivate() { }
// 此方法为公有
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
$myclass->MyProtected(); // 这行会产生一个致命错误
$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// 此方法为公有
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // 这行会产生一个致命错误
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>
Interfaces
Al usar interfaces (interface), se puede especificar qué métodos debe implementar una clase, sin necesidad de definir el contenido concreto de dichos métodos.
Las interfaces se definen medianteinterfacela palabra clave, de la misma manera que se define una clase estándar, pero todos los métodos definidos en ella están vacíos.
Todos los métodos definidos en una interfaz deben ser públicos; esta es una característica de las interfaces.
Para implementar una interfaz, se utilizaimplementsel operador. La clase debe implementar todos los métodos definidos en la interfaz; de lo contrario, se generará un error fatal. Una clase puede implementar varias interfaces, separando los nombres de las interfaces con comas.
<?php
// 声明一个'iTemplate'接口
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// 实现接口
class Template implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
Constantes
Los valores que permanecen constantes dentro de una clase se pueden definir como constantes. No se necesita usar el símbolo $ al definir o usar constantes.
El valor de una constante debe ser un valor fijo; no puede ser una variable, una propiedad de clase, el resultado de una operación matemática ni una llamada a función.
Desde PHP 5.3.0, se puede usar una variable para llamar dinámicamente a una clase. Pero el valor de esa variable no puede ser una palabra clave (como self, parent o static).
Ejemplo
<?php
class MyClass
{
const constant = '常量值';
function showConstant() {
echo self::constant . PHP_EOL;
}
}
echo MyClass::constant . PHP_EOL;
$classname = "MyClass";
echo $classname::constant . PHP_EOL; // 自 5.3.0 起
$class = new MyClass();
$class->showConstant();
echo $class::constant . PHP_EOL; // 自 PHP 5.3.0 起
?>
Clases abstractas
Cualquier clase que tenga al menos un método declarado como abstracto debe declararse a su vez como abstracta.
Las clases definidas como abstractas no pueden ser instanciadas.
Los métodos definidos como abstractos solo declaran su forma de invocación (parámetros); no pueden definir su implementación funcional concreta.
Al heredar de una clase abstracta, la subclase debe definir todos los métodos abstractos de la clase padre; además, el control de acceso de estos métodos debe ser igual al de la clase padre (o más permisivo). Por ejemplo, si un método abstracto se declara como protegido, el método implementado en la subclase debe declararse como protegido o público, y no puede definirse como privado.
<?php
abstract class AbstractClass
{
// 强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// 普通方法(非抽象方法)
public function printOut() {
print $this->getValue() . PHP_EOL;
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') . PHP_EOL;
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') . PHP_EOL;
?>
Al ejecutar el código anterior, el resultado es:
ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2
Además, los métodos de la subclase pueden incluir parámetros opcionales que no existan en los métodos abstractos de la clase padre.
Por ejemplo, si la subclase define un parámetro opcional que no está en la declaración del método abstracto de la clase padre, también funcionará correctamente.
<?php
abstract class AbstractClass
{
// 我们的抽象方法仅需要定义需要的参数
abstract protected function prefixName($name);
}
class ConcreteClass extends AbstractClass
{
// 我们的子类可以定义父类签名中不存在的可选参数
public function prefixName($name, $separator = ".") {
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>
El resultado es:
Mr. Pacman Mrs. Pacwoman
Palabra clave static
Si se declara una propiedad o método de clase como static (estático), se puede acceder directamente sin instanciar la clase.
Las propiedades estáticas no pueden ser accedidas a través de un objeto instanciado de la clase (pero los métodos estáticos sí pueden).
Debido a que los métodos estáticos no necesitan ser llamados a través de un objeto, la pseudo-variable $this no está disponible en los métodos estáticos.
Las propiedades estáticas no pueden ser accedidas por un objeto mediante el operador ->.
Desde PHP 5.3.0, se puede usar una variable para llamar dinámicamente a una clase. Pero el valor de esa variable no puede ser la palabra clave self, parent o static.
<?php
class Foo {
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . PHP_EOL;
$foo = new Foo();
print $foo->staticValue() . PHP_EOL;
?>
Al ejecutar el programa anterior, el resultado es:
foo foo
Palabra clave final
PHP 5 agregó la palabra clave final. Si un método de la clase padre se declara como final, la subclase no puede anularlo. Si una clase se declara como final, no puede ser heredada.
El siguiente código genera un error al ejecutarse:
<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called" . PHP_EOL;
}
final public function moreTesting() {
echo "BaseClass::moreTesting() called" . PHP_EOL;
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called" . PHP_EOL;
}
}
// 报错信息 Fatal error: Cannot override final method BaseClass::moreTesting()
?>
Llamar al constructor de la clase padre
PHP no llama automáticamente al constructor de la clase padre dentro del constructor de la subclase. Para ejecutar el constructor de la clase padre, es necesario llamarlo en el constructor de la subclase.parent::__construct() 。
<?php
class BaseClass {
function __construct() {
print "BaseClass 类中构造方法" . PHP_EOL;
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct(); // 子类构造方法不能自动调用父类的构造方法
print "SubClass 类中构造方法" . PHP_EOL;
}
}
class OtherSubClass extends BaseClass {
// 继承 BaseClass 的构造方法
}
// 调用 BaseClass 构造方法
$obj = new BaseClass();
// 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();
// 调用 BaseClass 构造方法
$obj = new OtherSubClass();
?>
Al ejecutar el programa anterior, el resultado es:
BaseClass 类中构造方法 BaseClass 类中构造方法 SubClass 类中构造方法 BaseClass 类中构造方法Otras extensiones