如何在PHP中使用Abstract Class来实现此机制?

问题描述

| 在过去的两天里,我一直在研究PHP中的OOPS概念,我发现Abstract Class是一个非常有用的概念,我想在我的应用程序中实现它。这就是为什么我要实现它。 我的应用程序由几个非结构化模式组成,该模式使用了几个没有任何层次结构的类,因此我不得不使用几个重复的代码。我想将其全部切割并适当地构造,基本上我想要做的是 定义一个不能从外部实例化的父类。 在此父类中定义所有属性,以便我可以将同一属性用于不同的子类。 定义可重用的类方法和对象,以便子类可以使用它,而无需一次又一次地定义它(继承)。 基本上,我的Abstract类应该能够继承可重用的方法和属性,同时它还应充当接口。 为了清楚地演示您,让我向您展示一些我一直在使用的示例代码。
public  $error = array(); //used to handle error mechanism and to hold the errors.
private $data = array();  //used with Accessor Methods (__set and __get)
private $validate;        //holds Validate Object
private $dbh;             //holds Database Object

public function __set($property,$value) {
    if( in_array($property,$this->data)) {
        return $this->data[$property] = $value;
    } else {
        return false;
    }
}

public function __get($property) {
    return \'Access Denied to Class Property [ \'.$property.\' ]\';
}
上面的代码几乎对每个类都重复,这就是我想在父类中定义一次并从那里控制机制的原因。 由于我仍然是许多OOP概念的新手,因此我无法理解如何使用Abstract Class实现我想要的东西。以下是我尝试使用哪种示例代码来声明抽象方法是错误的示例代码。
abstract class Property {
    protected $error = array();
    protected $data = array();
    protected $dbh;
    protected $validate;

    abstract protected function connectDB($dbhandle) {
        return $this->dbh = $dbhandle;
    }

    abstract protected function setValObj($valObj) {
        return $this->validate = $valObj;
    }

    public function __set($property,$value) {

    }

    public function __get($property) {

    }
}
这是我想做的。 子类启动时,应强制其定义抽象类中声明的方法。 Child类应该只能调用和传递争论,而不能扩展抽象方法。该机制应由父类处理。这就是我尝试在代码中执行的操作。 我知道我缺少某些东西,或者可能是我没有正确理解概念,有人可以向我解释我到底应该怎么做才能获得相同的结果。     

解决方法

1。定义一个不能从外部实例化的父类。 所有抽象类都不能实例化,只能扩展。这就是您已经拥有的:
abstract class Property {
转到下一个:   2。在此父类中定义所有属性,以便我可以将同一属性用于不同的子类。 只需将它们写入该抽象类(通常也称为基类或抽象基类或模板类)。从基类扩展的所有类都可以访问
protected
public
成员方法和属性。如果您使变量或函数为“ 5”,则仅可用于基类中的代码。 因此,只需定义要在所有扩展类之间共享的基类中要具有的所有内容,而只需键入一次即可。   3。定义可重用的类方法和对象,以使子类可以使用它而无需一次又一次地调用它(继承)。 这会自动工作。从基类扩展时,可以通过扩展类自动访问其中定义的公共和受保护的类方法。您不需要(但是除非用
final
指定,否则可以)不需要再次添加该功能以使其可用。例如。基类的所有公共方法都可以自动在其扩展的所有类上公开使用。 然后,您继续:   这是我想做的。      1。子类启动时,应强制其定义抽象类中声明的方法。 您可以通过将这些所需的方法定义为
abstract
来实现。抽象方法需要由扩展类实现。但是,您不能将代码放入基类的抽象方法中。剩下的用于扩展类。   2。 Child类应该只能调用和传递争论,而不能扩展抽象方法。该机制应由父类处理。这就是我尝试在代码中执行的操作。 如果要防止子类覆盖函数,请在基类中将其声明为6。最终方法无法进一步扩展。 但可能您想做一些技术上不可能的事情,例如防止在您需要扩展方法的同时扩展该方法。 在代码中,您正在使用魔术函数来访问属性/值。从名字的意义上讲,这些不算在内。因此,在类设计的很大一部分中,您将失去对继承的控制。 但是,您可以实现数组访问以提供getter / setter。它绑定到一个具体的接口,然后您可以禁止通过基类进行访问,并防止从该基类扩展的类扩展该区域。 让我知道您是否想要一些示例代码,SPL可能对您也很新。 通过ArrayAccess提供变量继承 由于您已经遇到了无法在可用的魔术函数__get()和__set()上轻易使用继承的问题,我想到了使访问具体部分保持不变(获取(设置),同时仍然可以命名属性变量。 PHP可用的已经执行此操作的接口是ArrayAccess。它旨在通过标准php数组(
[]
)中已知的样式提供对属性的访问,并且通常用于此目的。但是对于此示例,它的好处是已经提供了适合一般需求的接口。 首先演示如何使用此类:
# give birth to the object
$object = new PropertyClass; // one of your property classes

# get:
$value = $object[\'propertyA\'];

# set:
$object[\'propertyA\'] = \'new value\';

# unset:
unset($object[\'propertyA\']); // and gone ;)

# isset:
isset($object[\'propertyA\']); // true / false
好的,正如所示,它看起来像一个数组,但是是一个对象。 ѭ11的其余部分按已知方式工作,因此这不是限制性的,而是附加的。 正如您已经可以用此代码想象的那样,还必须有一个get and set例程来读取和设置诸如
__get()
__set()
之类的属性值。另外,必须有一些用于isset和unset的东西,所以有四个。这是ArrayAccess的接口定义:
ArrayAccess {
    /* Methods */
    abstract public boolean offsetExists ( mixed $offset )
    abstract public mixed offsetGet ( mixed $offset )
    abstract public void offsetSet ( mixed $offset,mixed $value )
    abstract public void offsetUnset ( mixed $offset )
}
您可以通过实现接口从PHP中扩展它。那不是
extends
,而是
implements
。这适用于PHP中的每个接口,但是该接口也很特别。它由SPL / PHP本身提供,在您的一类真正实现功能时,上面代码中描述的功能会自动添加到您的类中。 由于这些功能是公开可用的,因此您也可以自然地使用它们的名称来调用它们。 因此,实际上,此接口符合您要构建的属性对象的条件,并且会为您提供一个可以施加约束的接口。 因此剩下的唯一问题是:属性类的外观如何? 对变量属性类实现ArrayAccess
<?php
/**
 * Property Object base class based on ArrayAccess
 */
abstract class PropertyObject implements ArrayAccess
{
    /** Interface Methods */
    /**
     * implementing classes must return all names of their properties
     * in form of an array.
     */
    abstract protected function returnNames(); 

    /** class */

    /**
     * value store
     * 
     * @var array
     */
    private $store = array();

    /**
     * 
     * By this design,properties can only contain A-Z and a-z.
     *
     * look like.
     * 
     * @return bool
     */
    private function isValidPropertyName($name) {
        return ctype_alpha($name);
    }

    private function checkOffsetArgument($offset) {
        if ($this->isValidPropertyName($offset)) return;
        throw new InvalidArgumentException(sprintf(\'\"%s\" is not a valid property name.\',$offset));
    }

    private function setNames(array $names) {
        foreach($names as $name) {
            $this->checkOffsetArgument($name);
        }
        $len = count($names);
        $this->store = $len 
            ? array_combine($names,array_fill(0,$len,null)) 
            : array()
            ;
    }


    /**
     * final constructor to obtain control
     */
    final public function __construct() {
        $this->setNames($this->returnNames());
    }

    /**
     * ArrayAccess impl.
     * 
     * @return bool
     */
    public function offsetExists($offset) {
        $this->checkOffsetArgument($offset);
        return array_key_exists($offset,$this->store);
    }

    /**
     * ArrayAccess impl.
     * 
     * @return mixed
     */
    public function offsetGet ($offset) {
        $this->checkOffsetArgument($offset);
        return $this->store[$offset];
    }

    /**
     * ArrayAccess impl.
     */
    public function offsetSet($offset,$value) {
        $this->checkOffsetArgument($offset);
        if (!$this->offsetExists($offset)) {
            throw new InvalidArgumentException(sprintf(\'Property \"%s\" can not be set.\',$offset));
        }
        $this->store[$offset] = $value;
    }

    /**
     * ArrayAccess impl.
     */
    public function offsetUnset($offset) {
        $this->checkOffsetArgument($offset);
        unset($this->store[$offset]);
    }
}


/**
 * I feel so concrete.
 */
class ConcreteType extends PropertyObject
{
    protected function returnNames() {
        return array(\'propertyA\');
    }
}

$obj = new ConcreteType;

var_dump($obj[\'propertyA\']); # NULL,maybe you need other default values.

$obj[\'propertyA\'] = \'hello\';

var_dump($obj[\'propertyA\']); # string(5) \"hello\"

var_dump(isset($obj[\'propertyA\'])); # bool(true)

// this will trigger an exception
try {
    $obj[\'XProperty\'] = \'good night.\';
} catch (Exception $e) {
    var_dump($e->getMessage()); # string(36) \"Property \"XProperty\" can not be set.\"
}

// the following might be unwanted but can be prevented in base class:

unset($obj[\'propertyA\']);

var_dump(isset($obj[\'propertyA\'])); # bool(false)
    ,我认为您需要实现mixin接口。据我所知,PHP本身不支持此功能。一些PHP框架(例如Yii框架)是自己实现的。我在这里找到了一个例子。但是我相信您将能够找到更好的例子。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...