PHP, Object-Oriented Programming [Part 4]
- 11 de janeiro de 2009
Greetings Everyone!
Continuing from the previous post PHP, Object-Oriented Programming, Part 3, from now on we’ll move to object-oriented introduction.
2.4] Object Manipulation
get_class_methods
Returns an array with the names of methods from a specific class.
<?php
class Employee
{
function SetSalary()
{
}
function GetSalary()
{
}
function SetName()
{
}
function GetName()
{
}
}
print_r(get_class_methods('Employee'));
/*
Result:
Array
(
[0] => SetSalary
[1] => GetSalary
[2] => SetName
[3] => GetName
)
*/
?>
get_class_vars
Returns an array with the names of properties and contents of a specific class. Note that these are static values defined when creating the class.
<?php
class Employee
{
var $Code;
var $Name;
var $Salary = 586;
var $Department = 'Accounting';
function SetSalary()
{
}
function GetSalary()
{
}
}
print_r(get_class_vars('Employee'));
/*
Result:
Array
(
[Code] =>
[Name] =>
[Salary] => 586
[Department] => Accounting
)
*/
?>
get_object_vars
Returns an array with the names and contents of object properties. These are dynamic values that change according to the object’s lifecycle.
<?php
class Employee
{
var $Code;
var $Name;
var $Salary = 586;
var $Department = 'Accounting';
function SetSalary()
{
}
function GetSalary()
{
}
}
$jose = new Employee;
$jose->Code = 44;
$jose->Name = 'José da Silva';
$jose->Salary += 100;
$jose->Department = 'Finance';
print_r(get_object_vars($jose));
/*
Result:
Array
(
[Code] => 44
[Name] => José da Silva
[Salary] => 686
[Department] => Finance
)
*/
?>
get_class
Returns the name of the class to which an object belongs.
<?php
class Employee
{
var $Code;
var $Name;
function SetSalary()
{
}
function GetSalary()
{
}
}
$jose = new Employee;
echo get_class($jose);
/*
Result:
Employee
*/
?>
get_parent_class
Returns the name of the ancestor class (parent class). If the parameter is an object, returns the name of the ancestor class of the class to which the object belongs. If the parameter is a string, returns the name of the ancestor class of the class passed as parameter.
<?php
class Employee
{
var $Code;
var $Name;
}
class Intern extends Employee
{
var $Salary;
var $Scholarship;
}
$jose = new Intern;
echo get_parent_class($jose);
echo "\n"; // line break
echo get_parent_class('intern');
/*
Result:
Employee
Employee
*/
?>
is_subclass_of
Indicates if a specific object or class is derived from a specific class.
<?php
class Employee
{
var $Code;
var $Name;
}
class Intern extends Employee
{
var $Salary;
var $Scholarship;
}
$jose = new Intern;
if (is_subclass_of($jose, 'Employee'))
{
echo "Jose object class is derived from Employee";
}
echo "\n"; // line break
if (is_subclass_of('Intern', 'Employee'))
{
echo "Intern class is derived from Employee";
}
/*
Result:
Jose object class is derived from Employee
Intern class is derived from Employee
*/
?>
method_exists
Checks if a specific object has the described method. We can check for method existence before accidentally executing a non-existent method.
<?php
class Employee
{
var $Code;
var $Name;
function GetSalary()
{
}
function SetSalary()
{
}
}
$jose = new Employee;
if (method_exists($jose, 'SetName'))
{
echo 'Jose object has SetName() method';
}
if (method_exists($jose, 'SetSalary'))
{
echo 'Jose object has SetSalary() method';
}
/*
Result:
Jose object has SetSalary() method
*/
?>
call_user_func
Executes a function or method of a class passed as parameter. To execute a function, just pass its name as a string, and to execute an object method, just pass the parameter as an array containing the object at position 0 and the method to be executed at position 1. To execute static methods, just pass the class name instead of the object at position 0 of the array.
<?php
// simple call example
function myfunction()
{
echo "my function! \n";
}
call_user_func('myfunction');
// class declaration
class MyClass
{
function MyMethod()
{
echo "My method! \n";
}
}
// static method call
call_user_func(array('MyClass', 'MyMethod'));
// method call
$obj = new MyClass();
call_user_func(array($obj, 'MyMethod'));
/*
Result:
my function!
My method!
My method!
*/
?>
Advanced Introspection Functions
class_exists
Checks if a class has been defined:
<?php
if (class_exists('Employee')) {
echo "Employee class exists";
} else {
echo "Employee class doesn't exist";
}
?>
interface_exists
Checks if an interface has been defined:
<?php
interface MyInterface
{
public function requiredMethod();
}
if (interface_exists('MyInterface')) {
echo "MyInterface interface exists";
}
?>
property_exists
Checks if a property exists in a class or object:
<?php
class Employee
{
public $name;
private $salary;
}
$employee = new Employee();
var_dump(property_exists('Employee', 'name')); // true
var_dump(property_exists($employee, 'salary')); // true
var_dump(property_exists('Employee', 'age')); // false
?>
Reflection in PHP
Reflection allows examining classes, methods and properties at runtime.
ReflectionClass
<?php
class User
{
public $name;
private $password;
public function login($user, $password)
{
// login logic
}
private function encrypt($text)
{
// encryption logic
}
}
$reflection = new ReflectionClass('User');
// Get class information
echo "Class name: " . $reflection->getName() . "\n";
echo "Is instantiable: " . ($reflection->isInstantiable() ? 'Yes' : 'No') . "\n";
// List methods
echo "Methods:\n";
foreach ($reflection->getMethods() as $method) {
echo "- " . $method->getName() . " (" .
($method->isPublic() ? 'public' : 'private') . ")\n";
}
// List properties
echo "Properties:\n";
foreach ($reflection->getProperties() as $property) {
echo "- " . $property->getName() . " (" .
($property->isPublic() ? 'public' : 'private') . ")\n";
}
?>
ReflectionMethod
<?php
$reflection = new ReflectionClass('User');
$method = $reflection->getMethod('login');
echo "Method name: " . $method->getName() . "\n";
echo "Number of parameters: " . $method->getNumberOfParameters() . "\n";
echo "Required parameters: " . $method->getNumberOfRequiredParameters() . "\n";
// List parameters
foreach ($method->getParameters() as $parameter) {
echo "Parameter: " . $parameter->getName();
if ($parameter->isOptional()) {
echo " (optional)";
}
echo "\n";
}
?>
Practical Applications
Factory Pattern with Reflection
<?php
class UserFactory
{
public static function create($type, $data = array())
{
$class = 'User' . ucfirst($type);
if (!class_exists($class)) {
throw new Exception("User type '$type' doesn't exist");
}
$reflection = new ReflectionClass($class);
$object = $reflection->newInstance();
// Configure properties using reflection
foreach ($data as $property => $value) {
if (property_exists($class, $property)) {
$object->$property = $value;
}
}
return $object;
}
}
class UserAdmin
{
public $name;
public $level = 'admin';
}
class UserCommon
{
public $name;
public $level = 'common';
}
// Usage
$admin = UserFactory::create('admin', ['name' => 'John']);
$common = UserFactory::create('common', ['name' => 'Maria']);
?>
Automatic Validator
<?php
class Validator
{
public static function validate($object)
{
$reflection = new ReflectionClass($object);
$errors = array();
foreach ($reflection->getProperties() as $property) {
$name = $property->getName();
$value = $property->getValue($object);
// Validation based on property name
if (strpos($name, 'email') !== false) {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email: $name";
}
}
if (strpos($name, 'required') !== false && empty($value)) {
$errors[] = "Required field: $name";
}
}
return $errors;
}
}
class ContactForm
{
public $emailRequired;
public $nameRequired;
public $phone;
}
$form = new ContactForm();
$form->emailRequired = 'invalid-email';
$form->nameRequired = '';
$form->phone = '1234567890';
$errors = Validator::validate($form);
foreach ($errors as $error) {
echo $error . "\n";
}
?>
Dynamic Plugin System
<?php
class PluginManager
{
private $plugins = array();
public function loadPlugin($className)
{
if (!class_exists($className)) {
return false;
}
$reflection = new ReflectionClass($className);
// Check if implements plugin interface
if (!$reflection->implementsInterface('IPlugin')) {
throw new Exception("$className must implement IPlugin");
}
$plugin = $reflection->newInstance();
$this->plugins[] = $plugin;
return true;
}
public function executePlugins($event, $data = array())
{
foreach ($this->plugins as $plugin) {
$reflection = new ReflectionClass($plugin);
if ($reflection->hasMethod($event)) {
$method = $reflection->getMethod($event);
$method->invoke($plugin, $data);
}
}
}
}
interface IPlugin
{
public function onInit();
}
class LogPlugin implements IPlugin
{
public function onInit()
{
echo "Log plugin started\n";
}
public function onUserLogin($data)
{
echo "User logged in: " . $data['name'] . "\n";
}
}
// Usage
$manager = new PluginManager();
$manager->loadPlugin('LogPlugin');
$manager->executePlugins('onInit');
$manager->executePlugins('onUserLogin', ['name' => 'John']);
?>
Best Practices
1. Use Reflection Moderately
- Performance: Reflection is slower than direct access
- Complexity: Can make code hard to understand
- Cache: Cache reflection results when possible
2. Input Validation
<?php
function callMethod($object, $method, $parameters = array())
{
if (!is_object($object)) {
throw new InvalidArgumentException('First parameter must be object');
}
if (!method_exists($object, $method)) {
throw new BadMethodCallException("Method '$method' doesn't exist");
}
$reflection = new ReflectionMethod($object, $method);
if (!$reflection->isPublic()) {
throw new BadMethodCallException("Method '$method' is not public");
}
return $reflection->invokeArgs($object, $parameters);
}
?>
3. Clear Documentation
<?php
/**
* Utility class for object introspection
*
* Provides methods to examine object properties and methods
* at runtime using PHP reflection
*/
class Introspector
{
/**
* Lists all public methods of an object
*
* @param object $object The object to be examined
* @return array List of public method names
* @throws InvalidArgumentException if parameter is not an object
*/
public static function listPublicMethods($object)
{
if (!is_object($object)) {
throw new InvalidArgumentException('Parameter must be an object');
}
$reflection = new ReflectionClass($object);
$publicMethods = array();
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$publicMethods[] = $method->getName();
}
return $publicMethods;
}
}
?>
Conclusion
That’s all for today folks!
Object manipulation functions in PHP are powerful tools that allow:
Resources Learned
- get_class_methods: List class methods
- get_class_vars: Get static properties
- get_object_vars: Get dynamic properties
- method_exists: Check method existence
- call_user_func: Execute methods dynamically
- Reflection: Advanced object introspection
Practical Applications
- Factory Pattern: Dynamic object creation
- Automatic validation: Based on conventions
- Plugin systems: Dynamic loading
- Flexible APIs: Configurable methods
Next Steps
In the next part we’ll cover more advanced object-oriented concepts, including inheritance, polymorphism and interfaces.
The ability to examine and manipulate objects dynamically is one of the most powerful features of modern PHP!
[]‘s