问题
PHP Class Using Same Name as Trait Function
Refer to the question I just asked above here. Here was my original code.
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?
}
}
I can call the trait function like this thanks to the answer to the question.
class client{
use sampletrait {
hello as protected sampletrait_hello;
}
function hello(){
$this->sampletrait_hello();
echo "hello from class";
}
}
My question is if my class client did not have a function hello() but wanted to call it is this possible?
So for example...
trait sampletrait{
function hello(){
echo "hello from trait";
}
}
class client{
use sampletrait {
hello as protected sampletrait_hello;
}
}
I'm aware that I could just simply say use sampletrait; and it would have the function but in my use case I can't do that either. Is it possible to have the aliased name but still use the trait name default if it does not exist in the class?
Extra Information
My exact use case involves PHP-ActiveRecord
I have a trait called 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']);
}
}
}
}
?>
I use this in my model Client like so...
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;
}
}
?>
I am trying to use this to get around phpactiverecords unique check bug since it does not work in there system for a project I'm working on.
It uses a callback like this (before_validation_on_update_callback), where it has to have that name.
I wanted to use a trait to include it in all my models for unique checking easily.
Refer to this (http://www.phpactiverecord.org/projects/main/wiki/Callbacks)
回答1:
Try setting public on the trait function and then protected when you rename
trait sampletrait{
public function hello(){
echo "hello from trait";
}
}
class client{
use sampletrait {
hello as protected sampletrait_hello;
}
}
$c = new client();
$c->hello();
As said here PHP Class Using Same Name as Trait Function both hello and sampletrait_hello will exist, but as hello is public and sampletrait_hello protected only hello will be callable from an outer scope.
And if you overwrite hello, you will be able to call sampletrait_hello inside it.
来源:https://stackoverflow.com/questions/43702562/use-trait-function-with-same-name-but-optionally