【问题标题】:Use Trait Function with Same Name but Optionally使用具有相同名称但可选的特征函数
【发布时间】:2017-04-30 03:15:44
【问题描述】:

PHP Class Using Same Name as Trait Function

请参阅我刚才在此处提出的问题。这是我的原始代码。

trait sampletrait{
   function hello(){
      echo "hello from trait";
   }
}

class client{
   use sampletrait;

   function hello(){
      echo "hello from class";
      //From within here, how do I call traits hello() function also?
   }
}

感谢问题的答案,我可以像这样调用特征函数。

class client{
   use sampletrait {
       hello as protected sampletrait_hello;
   }

   function hello(){
      $this->sampletrait_hello();
      echo "hello from class";
   }
}

我的问题是,如果我的类客户端没有函数 hello() 但想调用它,这可能吗?

比如说……

trait sampletrait{
   function hello(){
      echo "hello from trait";
   }
}

class client{
   use sampletrait {
      hello as protected sampletrait_hello; 
   }
}

我知道我可以简单地说使用 sampletrait;它会有这个功能,但在我的用例中我也不能这样做。如果类中不存在,是否可以使用别名但仍使用默认的特征名称?

额外信息

我的确切用例涉及 PHP-ActiveRecord

我有一个叫做 uniquecheck 的特质

trait uniquecheck {

    //@JA - Used temporarely to determine if editing for the unique checker
    static $isEditing = false;

    //@JA - This is used by PHPActiveRecord to trigger events before validation on update calls only.
    static $before_validation_on_update = array('before_validation_on_update_callback');

    //@JA - This is function used as callback from PHPActiveRecord
    public function before_validation_on_update_callback(){
        self::$isEditing = true; //@JA - Requires Uniquecheck trait to work
    }

    //@JA - This function can do single and multi-unique checks.
    //@JA - This is programmed to be replaced at a later date when validates_uniqueness_of is fixed (http://www.phpactiverecord.org/projects/main/wiki/Validations#validates_uniqueness_of)
    //@JA - EXAMPLES
    //SINGLE    -- array('name','message' => 'Can't do this')
    //MULTIPLE  -- array( array('name1','name2'), 'message' => 'can't do this and that together')
    //@JA - To be clear multiple does not mean 2 different uniques but a unique on 2 columns.  Just use this function twice for 2 separate unique checks.
    public function uniquecheck($rules = array()) {

        $classname = get_class($this);

        //@JA - Basic validation to confirm assumptions for function properties
        if(count($rules)<=0){
            die('uniquecheck.php -> Property array can not be empty');
        }

        //@JA - If its an array use the MULTIPLE method
        if(is_array($rules[0])){
            //@JA - First create the condition string
            $conditionstring = '';
            $conditionarray = array();

            $uniques = $rules[0];
            foreach($uniques as $unique){
                $conditionstring .= "$unique = ? AND "; 
            }
            $conditionstring = substr($conditionstring, 0, -5);

            //@JA - Then generate the array we will use for the conditions
            $conditionarray['conditions'][] = $conditionstring;
            foreach($uniques as $unique){
                $conditionarray['conditions'][] = $this->read_attribute($unique);
            }

            $results = $classname::find('all',$conditionarray);

            if($classname::$isEditing == true){
                die('was editing');
            }else{
                die('was creating');
            }

            //@JA - If in edit mode, if the values are exactly the same as it was before then ignore this check.
            if (count($results)>=1) {
                foreach($uniques as $unique){
                    $this->errors->add($unique, $rules['message']);
                }
            }

        }else{ //@JA - Otherwise use the SINGLE method
            $unique = $rules[0];
            $results = $classname::find('all',array('conditions' => array("$unique = ?", $this->read_attribute($unique))));

            //@JA - If there is more then 1 result then its not unique!
            if (count($results)>=1) {
                $this->errors->add($unique, $rules['message']);
            }
        }       
    }
}

?>

我在我的模型客户端中使用它......

class Client extends ActiveRecord\Model {

    use foreignkeycheck;

    use uniquecheck {
       before_validation_on_update_callback as protected uniquecheck_before_validation_on_update_callback; 
    }

    static $before_destroy = array('before_destroy_callback');

    //@gv hide columns that are not in use right now
    static $columnsToHide = array(
        'affiliate_code',
        'autopay',
        'stripe_customer_id',
        'quickbooks_client_id',
        'stripe_customer_info',
        'stripe_customer_info_last_update',
        'textingnumber'
    );
    static $easy_name = "Client";
    static $validates_presence_of = array(
        array('clienttype_id'),
        array('company_id'),
        array('contactfirstname'),
        array('contactlastname'),
        array('contactphonenumber')        
    );
    static $validates_size_of = array(
        array('contactfirstname', 'within' => array(1, 50)),
        array('contactlastname', 'within' => array(1, 50)),        
        array('contactaddress', 'within' => array(1, 120), 'allow_null' => false),
        array('companyaddress', 'within' => array(1, 120), 'allow_null' => true),
        array('companyname', 'within' => array(1, 75), 'allow_null' => true),                
    );
//    static $validates_uniqueness_of = array(
//        array('affiliate_code', 'allow_null' => true),
//        array(array('contactfirstname', 'contactlastname', 'contactemail', 'contactphonenumber', 'contactaddress'),
//            'message' => 'Can\'t have duplicate client.')
//    );

    static $validates_format_of = array(
        array('contactemail', 'with' => '/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}\b/sim',
            'message' => 'Must be a correctly formatted email.', 'allow_blank' => true, 'allow_null' => true),
        array('companyemail', 'with' => '/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}\b/sim',
            'message' => 'Must be a correctly formatted email.', 'allow_blank' => true, 'allow_null' => true),
        array('companyphonenumber', 'with' => '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i', 
            'message' => 'Phone number is invalid', 'allow_blank' => true, 'allow_null' => true),
        array('contactphonenumber', 'with' => '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i', 
            'message' => 'Phone number is invalid', 'allow_blank' => true, 'allow_null' => false)
    );

    //This allows you to use your own as well as still call the uniquechecks before_validation callback in case this method is not needed.
    public function before_validation_on_update_callback(){
        $this->uniquecheck_before_validation_on_update_callback();
    }

    public function before_destroy_callback(){

        $conn = SELF::connection();
        $conn->transaction();

        try {
            //USER *********
            //Delete the associated user as well.
            $related_users = User::find('all',array(
                'conditions' => array(
                    'client_id' => $this->id)
            ));

            foreach($related_users as $user){
                $user->delete();
            }

            //PROPERTIES ********
            //Delete all properties of the client, which in turn delets all routes & visits
            $related_properties = Property::find('all',array(
                'conditions' => array(
                    'client_id' => $this->id)
            ));

            foreach($related_properties as $property){
                $property->delete();
            }

            //Only have to delete the user, because deletes will cascade down
            $conn->commit();
        } catch (Exception $e) {            
            $conn->rollback();
        }

        return true; //will actually delete the client now.
    }

    public function validate() {
        //Thought about putting user validation in here, but decided against it.
        //Multi-unique check FAILS to work if the parameter is not passsed for one of the multi-uniques.  This is BUG in PHP Active Record.
        //Does not show message correctly for multi-uniques either.  This is ALSO a bug in PHP Active Record.

        //@JA - Uses multi-unique check.  Its only not allowed if all 4 of these values are the same since its obviously duplicate at that point
        $this->uniquecheck(array(array('company_id','contactfirstname', 'contactlastname', 'contactphonenumber', 'contactaddress'),'message' => 'Can\'t have duplicate client.'));

        $this->foreignkeycheck('Clienttype');
        $this->foreignkeycheck('Company');
        $this->foreignkeycheck('Affiliate', 'affiliate_code', true); //Special case where foreign key is not _id, true sent to indicate validate is optional only if a value is not null.
    }

    public function getReadableColumnNames($flip = false) {
        $readableColumns = array();

        $readableColumns["contactfirstname"] = "First Name";
        $readableColumns["contactlastname"] = "Last Name";
        $readableColumns["contactphonenumber"] = "Phone Number";
        $readableColumns["contactemail"] = "Email";
        $readableColumns["contactaddress"] = "Address";
        $readableColumns["companyaddress"] = "Company Address";
        $readableColumns["companyemail"] = "Company Email";
        $readableColumns["companyname"] = "Company Name";
        $readableColumns["companyphonenumber"] = "Company Phone #";
        $readableColumns["affiliate_code"] = "Affiliate #";
        $readableColumns["clienttype_id"] = "Client Type";
        $readableColumns["company_id"] = "Company";
        $readableColumns["stripe_customer_id"] = "Stripe Customer ID";
        $readableColumns["stripe_customer_info"] = "Stripe Customer Info";
        $readableColumns["stripe_customer_info_last_update"] = "Stripe Info Last Update";
        $readableColumns["welcome_email_sent"] = "Welcome Email Sent?";
        $readableColumns["autopay"] = "Auto Pay?";
        $readableColumns["active"] = "Active?";

        if ($flip == true) {
            $readableColumns = array_flip($readableColumns); //swap keys and values~
        }
        return $readableColumns;
    }

    public function getDefaultColumns() {
        $defaultColumns = array();

        $defaultColumns[] = "contactfirstname"; //first sort order
        $defaultColumns[] = "contactlastname"; //second sort order
        $defaultColumns[] = "contactphonenumber";
        $defaultColumns[] = "contactemail"; //etc...

        return $defaultColumns;
    }

    public function getColumnExceptions() {
        $tableNames = array();

        return $tableNames;
    }

    public function getBatchActions() {
        $batchActions = array();

        //$batchActions['Text to Appear'] = 'ClassName' 
        //For JS File To Call Correct Function ^^^^
        //Order of array determines order in respective dropdown menu.

        $batchActions["Make Inactive"] = "batch_make_inactive";
        $batchActions["Send Email"] = "batch_send_email";
        $batchActions["Send Welcome Email"] = "batch_send_client_welcomeEmail";

        return $batchActions;
    }

    public function getRowActions() {
        $rowActions = array();

        $rowActions["Edit"] = array("edit_typename", true); //Call generic typename edit function, true means this is the item that shows first.
        $rowActions["View Pictures"] = array("view_pictures_for_client", false); //shortcut to prefill information for property~
        $rowActions["Add Property"] = array("add_property_for_client", false); //shortcut to prefill information for property~
        //$rowActions["Update Quickbooks"] = array("qb_update_customer", false); //shortcut to add customer to quickbooks if connected.
        $rowActions["Create User ID"] = array("create_userid_for_client", false); //shortcut method to create user_id straight from the client~
        $rowActions["Send Welcome Email"] = array("send_client_welcome_email", false);
        $rowActions["Make Inactive"] = array("allinactive_client", false); //will make the user inactive, property and user_id, along with recurring invoices, estimates, invoices that were referenced by client.
        $rowActions["Make Active"] = array("allactive_client", false);
        $rowActions["Delete"] = array("delete_typename", false);   //call to generic typename delete function
        //@gv Functions that do not work and not part of Release 1.0
        //$rowActions["Add Estimate"]         = array("add_estimate_for_client",false); //shortcut to prefill information for property~
        //$rowActions["Add Invoice"]          = array("add_invoice_for_client",false); //shortcut to prefill information for property~
        //$rowActions["Add To Quickbooks"]    = array("qb_add_customer",false); //shortcut to add customer to quickbooks if connected.
        //$rowActions["Make Inactive"]        = array("inactive_typename",false);   //Way to filter results if you desired by clients that are not relevant anymore.
        //$rowActions["Send Email"]           = array("send_client_email",false);
        //$rowActions["Send Text"]            = array("text_client",false);

        return $rowActions;
    }

    public function getColumnInterestedColumns() {
        $columnInterestedColumns = array();

        $columnInterestedColumns["clienttype_id"] = array("name");
        $columnInterestedColumns["company_id"] = array("companyname");
        $columnInterestedColumns["client_id"] = array("contactfirstname", "contactlastname"); //external reference.

        return $columnInterestedColumns;
    }

    //This function indicates to the UI what fields are dependent upon others for purpose of 'flow' for new and edit areas.
    //Happens in 2 areas, on initial PHP creation uses this to hide the field, and upon the restricted fields parent values taking on a value or losing a value.
    public function getColumnRestrictions() {
        global $user;
        $restrictedColumns = array();

        //$restrictedColumns["property_id"] =   array("client_id");//this means that property_id can not show in UI until client_id is set.

        return $restrictedColumns;
    }
}

?>

我正在尝试使用它来解决 phpactiverecords 唯一检查错误,因为它不适用于我正在处理的项目的系统。

它使用这样的回调 (before_validation_on_update_callback),它必须具有该名称。

我想使用一个特征将它包含在我的所有模型中,以便轻松地进行唯一检查。

参考这个 (http://www.phpactiverecord.org/projects/main/wiki/Callbacks)

【问题讨论】:

    标签: php traits


    【解决方案1】:

    尝试在 trait 函数上设置 public,然后在重命名时进行保护

    trait sampletrait{
       public function hello(){
          echo "hello from trait";
       }
    }
    
    class client{
       use sampletrait {
          hello as protected sampletrait_hello; 
       }
    }
    
    $c = new client();
    $c->hello();
    

    正如这里所说的PHP Class Using Same Name as Trait Function hello 和 sampletrait_hello 都将存在,但是由于 hello 是公共的并且 sampletrait_hello 受保护,只有 hello 可以从外部范围调用。

    如果你覆盖 hello,你就可以在里面调用 sampletrait_hello。

    【讨论】:

    • 当我这样做时,我没有收到错误,但似乎也没有发生任何事情,这很奇怪吗?就好像该方法永远不会被调用。这对你有用吗?我会尽快验证我的确切 php 版本...
    • PHP 版本 7.0.15-0ubuntu0.16.04.4
    • 我在 php 7.1.4 上运行良好,这很奇怪
    • 也许我需要升级到 7.1.4 嗯?在尝试其他一些解决方案后不久,我也会尝试这样做。
    • 我不知道,我只是查看了补丁说明 (php.net/manual/en/migration71.php) 没有关于特性的内容
    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2022-11-07
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 2010-09-29
    相关资源
    最近更新 更多