• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 225
  • Last Modified:

abstracting classes

I do not understand
what difference is
$address_residence->address_type_id = 1;
and regular address types (street address, city_name, subdivision_name)

If parent class is declared abstract, am I forced to use the child classes (new AddressBussiness, new AddressResidence, new AddressPark) in demo.php and not the parent class (new Address)

and could you explain this tutorial

from Lynda.com object oriented php tutorial
abstracting classes


 * Physical address. 
abstract class Address {
  const ADDRESS_TYPE_PARK = 3;
  // Address types.
  static public $valid_address_types = array(
    Address::ADDRESS_TYPE_RESIDENCE => 'Residence',
    Address::ADDRESS_TYPE_BUSINESS => 'Business',
    Address::ADDRESS_TYPE_PARK => 'Park',
  // Street address.
  public $street_address_1;
  public $street_address_2;
  // Name of the City.
  public $city_name;
  // Name of the subdivison.
  public $subdivision_name;
  // Postal code.
  protected $_postal_code;
  // Name of the Country.
  public $country_name;
  // Primary key of an Address.
  protected $_address_id;
  // Address type id.
  protected $_address_type_id;
  // When the record was created and last updated.
  protected $_time_created;
  protected $_time_updated;
   * Constructor.
   * @param array $data Optional array of property names and values.
  function __construct($data = array()) {
    $this->_time_created = time();
    // Ensure that the Address can be populated.
    if (!is_array($data)) {
      trigger_error('Unable to construct address with a ' . get_class($name));
    // If there is at least one value, populate the Address with it.
    if (count($data) > 0) {
      foreach ($data as $name => $value) {
        // Special case for protected properties.
        if (in_array($name, array(
        ))) {
          $name = '_' . $name;
        $this->$name = $value;
   * Magic __get.
   * @param string $name 
   * @return mixed
  function __get($name) {
    // Postal code lookup if unset.
    if (!$this->_postal_code) {
      $this->_postal_code = $this->_postal_code_guess();
    // Attempt to return a protected property by name.
    $protected_property_name = '_' . $name;
    if (property_exists($this, $protected_property_name)) {
      return $this->$protected_property_name;
    // Unable to access property; trigger error.
    trigger_error('Undefined property via __get: ' . $name);
    return NULL;
   * Magic __set.
   * @param string $name
   * @param mixed $value 
  function __set($name, $value) {
   /* // Only set valid address type id.
    if ('address_type_id' == $name) {
    // Allow anything to set the postal code.
    if ('postal_code' == $name) {
      $this->$name = $value;
    // Unable to access property; trigger error.
    trigger_error('Undefined or unallowed property via __set(): ' . $name);
   * Magic __toString.
   * @return string 
  function __toString() {
    return $this->display();
  * force extending classes to implement init method
  abstract protected function _init();
   * Guess the postal code given the subdivision and city name.
   * @todo Replace with a database lookup.
   * @return string 
  protected function _postal_code_guess() {
    $db = Database::getInstance();
    $mysqli = $db->getConnection();
    $sql_query  = 'SELECT postal_code ';
    $sql_query .= 'FROM location ';
    $city_name = $mysqli->real_escape_string($this->city_name);
    $sql_query .= 'WHERE city_name = "' . $city_name . '" ';
    $subdivision_name = $mysqli->real_escape_string($this->subdivision_name);
    $sql_query .= 'AND subdivision_name = "' . $subdivision_name . '" ';
    $result = $mysqli->query($sql_query);
    if ($row = $result->fetch_assoc()) {
      return $row['postal_code'];
   * Display an address in HTML.
   * @return string 
  function display() {
    $output = '';
    // Street address.
    $output .= $this->street_address_1;
    if ($this->street_address_2) {
      $output .= '<br/>' . $this->street_address_2;
    // City, Subdivision Postal.
    $output .= '<br/>';
    $output .= $this->city_name . ', ' . $this->subdivision_name;
    $output .= ' ' . $this->postal_code;
    // Country.
    $output .= '<br/>';
    $output .= $this->country_name;
    return $output;
   * Determine if an address type is valid.
   * @param int $address_type_id
   * @return boolean
  static public function isValidAddressTypeId($address_type_id) {
    return array_key_exists($address_type_id, self::$valid_address_types);
   * If valid, set the address type id.
   * @param int $address_type_id 
  protected function _setAddressTypeId($address_type_id) {
    if (self::isValidAddressTypeId($address_type_id)) {
      $this->_address_type_id = $address_type_id;

Open in new window

* define autoloader
* @param string $class_name
function __autoload($class_name){
  include 'class.' .$class_name. '.inc';

echo '<h2>Instantiating AddressResidence()</h2>';
$address_residence = new AddressResidence();

echo '<h2>Setting properties...</h2>';
$address_residence->street_address_1 = '555 Fake Street';
$address_residence->city_name = 'Townsville';
$address_residence->subdivision_name = 'State';
$address_residence->country_name = 'United States of America';
$address_residence->address_type_id = 1;
echo $address_residence;
echo '<pre>';
echo '</pre>';

echo '<h2>Testing AddressBusiness __construct with an array</h2>';
$address_business = new AddressBusiness(array(
  'street_address_1' => '123 Phony Ave',
  'city_name' => 'Villageland',
  'subdivision_name' => 'Region',
  'country_name' => 'Canada',
echo $address_business;
echo '<pre>';
echo '</pre>';

Open in new window

00:00	Visibility scope is not the only object-oriented way to restrict access.
00:04	PHP5 also introduced the concept of abstract classes and methods.
00:09	If a class is defined as abstract, it cannot be instantiated.
00:14	If you define a method as abstract, then any class that extends that
00:18	abstract class containing the method must also declare a method with the
00:22	same name and arguments.
00:24	Further, if a class has an abstract method, then the class itself must be abstract.
00:30	This solves the problem of the generic address class, and provides a mechanism to
00:34	specify the behavior of any child classes.
00:38	Open the address class, scroll to the top, and add the word "abstract" at the
00:43	beginning of the class declaration.
00:45	Save the address, then switch to your browser, and refresh the demo.
00:50	At the bottom, the attempted instantiation of the generic address class has been
00:54	disallowed, and caused a fatal error.
00:56	This is a good thing, as it forces the developer to be specific.
01:00	Edit the demo, and re-factor the second address instance to be a business address,
01:04	including the variable name. AddressBusiness. address_business for the variable
01:13	name as well. And then, add a var_ export at the end, so we can inspect the
01:22	contents. Save the demo, go back to the browser, and refresh.
01:28	The business address is now displayed correctly.
01:31	However, there is a data inconsistency; it's the correct class (AddressBusiness),
01:36	but the _address_type_id is not set.
01:40	Missing property values is a common development problem.
01:43	When working with multiple similar objects, there can be a lot of easily
01:47	forgotten details to keep track of.
01:49	The solution is to initialize objects automatically, so you don't have to
01:53	remember to do it, but what's the best way to initialize them?
01:57	Your first reaction may be to make the construct magic method abstract. This
02:01	would technically work, but you'd end up with a lot of copied and pasted code, as
02:06	everything in construct would have to be duplicated.
02:09	This can easily lead to a fragile system, where re-factoring or adding new
02:13	functionality becomes cumbersome.
02:15	It's not a best practice, and not very object-oriented.
02:19	Instead, I'm going to construct the object in the parent, then call an
02:22	abstract initializer.
02:24	This way, common behavior in the parent's construct method always executes upon
02:28	instantiation. Then, custom behavior can be put in each child's
02:32	initialization method. Neat!
02:35	With these relationships, visibility is also a factor, and abstract method
02:39	visibility can be a bit tricky.
02:41	Methods that implement an abstract method will also need to have the same scope,
02:46	or something a little bit less restrictive.
02:48	If an abstract method is declared as public, I won't be able to change it to private.
02:53	However, the opposite is true.
02:56	I can make an abstract private method public.
02:59	It's a one-way change.
03:01	You can relax the scope restriction, but not make it stricter.
03:05	This prevents a situation when you're expecting to be able to do something, but
03:08	for some strange reason, you are prevented by scope.
03:11	To practically apply this to the addresses, I'm going to require that extending
03:15	classes set the address type id upon creation.
03:19	Let's open the Address class.
03:21	After the magic method toString, define a new abstract protected method called
03:27	init, abstract protected function _init().
03:36	Force extending classes to implement init method, then add a call to the
03:44	initialization method at the beginning of the constructor. $this->init. Save the
03:53	address class, then go to your browser, and refresh.
03:58	You will see an immediate error.
03:59	The AddressResidence class contains an abstract method that needs to be defined.
04:04	So, open the AddressResidence class, and declare the private function initialized.
04:09	protected function _init(). Set the address type id to the constant from the
04:15	address class, using your validating method:
04:18	$this-> setAddressTypeIDAddress::ADDRESS_TYPE_RESIDENCE.
04:27	Add some documentation, and copy the contents of this method, and paste it into
04:39	the business address. ADDRESS_TYPE_ BUSINESS. And, again for the Park. Save, then
04:52	return to your browser, and refresh.
04:55	You'll see that the _address_type_id for the business is now set correctly.
04:59	However, a redundancy has now been introduced with the potential for corruption.
05:04	You can still set the _address_type_ id manually, and if you look at the demo,
05:08	AddressResidence is doing just that.
05:12	You can just remove the _address_type_id, but that treats the symptom, not the problem.
05:16	Return to the address class, and navigate to the magic set method.
05:20	Remove the special case for _address_ type_id. Save, then refresh the demo.
05:28	You will see a notice for undefined or unallowed property.
05:31	Data corruption is now prevented.
05:33	Edit the demo, and remove the now- broken attempt to set the _address_type_id.
05:39	Then save, and refresh.
05:43	The notice is now gone, and execution is error-free.
05:47	In the next segment, I'm going to demonstrate how to implement a common
05:50	interface across all these child address classes without having to know what
05:54	kind of an address type it is.

Open in new window

1 Solution
Ray PaseurCommented:
See http://www.php.net/manual/en/language.oop5.abstract.php#82111

Abstract classes share some characteristics with interfaces in that they both produce a "contract" between the programmers working on the project.

An interface tells what methods must be implemented in the class that implements the interface, but it does not have any methods of its own.

An abstract class may have some methods that are fully implemented in the class definition, and may have some methods that are abstract, meaning that they must be defined in the class that extends the abstract class.
rgb192Author Commented:
thank you for abstract and interface definition.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now