Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a254d11
commit 8dc27c3
Showing
40 changed files
with
5,619 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
<?php | ||
|
||
/** | ||
* Class WPLib_Base | ||
*/ | ||
abstract class WPLib_Base { | ||
|
||
/** | ||
* @var array Capture any extra $args passed for which there are no properties. | ||
*/ | ||
var $extra_args = array(); | ||
|
||
/** | ||
* @var WPLib_Base|null If not null contains reference to containing object. | ||
*/ | ||
var $owner; | ||
|
||
/** | ||
* @var bool If true will trigger an error if a non-existent method or property is accessed. | ||
*/ | ||
private $_trigger_error = true; | ||
|
||
/** | ||
* @param array|string|object $args | ||
*/ | ||
function __construct( $args = array() ) { | ||
|
||
$this->set_state( $args ); | ||
|
||
} | ||
|
||
/** | ||
* Set the object state given an array of $args with elements that match property names. | ||
* | ||
* @not And array elements not found as properties will be assigned to the property array $this->extra_args. | ||
* | ||
* @param array|object $args | ||
*/ | ||
function set_state( $args ) { | ||
|
||
$args = wp_parse_args( $args ); | ||
|
||
foreach ( $args as $name => $value ) { | ||
|
||
if ( 'extra_args' != $name && property_exists( $this, $name ) ) { | ||
|
||
$this->{$name} = $value; | ||
|
||
} else if ( property_exists( $this, $protected_name = "_{$name}" ) ) { | ||
|
||
$this->{$protected_name} = $value; | ||
|
||
} else { | ||
|
||
$this->extra_args[ $name ] = $value; | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* Return a class constant for the called instance. | ||
* | ||
* @param string $constant_name | ||
* @param string $class_name | ||
* | ||
* @return mixed|null | ||
*/ | ||
function constant( $constant_name, $class_name = null ) { | ||
|
||
if ( is_null( $class_name ) ) { | ||
|
||
$class_name = get_class( $this ); | ||
|
||
} | ||
|
||
return defined( $constant_ref = "{$class_name}::{$constant_name}" ) ? constant( $constant_ref ) : null; | ||
|
||
} | ||
|
||
/** | ||
* @param string $action | ||
* @param int $priority | ||
*/ | ||
static function add_class_action( $action, $priority = 10 ) { | ||
|
||
$hook = "_{$action}" . ( 10 != $priority ? "_{$priority}" : '' ); | ||
add_action( $action, array( get_called_class(), $hook ), $priority, 99 ); | ||
|
||
} | ||
|
||
/** | ||
* @param string $filter | ||
* @param int $priority | ||
*/ | ||
static function add_class_filter( $filter, $priority = 10 ) { | ||
|
||
$hook = "_{$filter}" . ( 10 != $priority ? "_{$priority}" : '' ); | ||
add_filter( $filter, array( get_called_class(), $hook ), $priority, 99 ); | ||
|
||
} | ||
|
||
/** | ||
* @param string $action | ||
* @param int $priority | ||
*/ | ||
static function remove_class_action( $action, $priority = 10 ) { | ||
|
||
$hook = "_{$action}" . ( 10 != $priority ? "_{$priority}" : '' ); | ||
remove_action( $action, array( get_called_class(), $hook ), $priority, 99 ); | ||
|
||
} | ||
|
||
/** | ||
* @param string $filter | ||
* @param int $priority | ||
*/ | ||
static function remove_class_filter( $filter, $priority = 10 ) { | ||
|
||
$hook = "_{$filter}" . ( 10 != $priority ? "_{$priority}" : '' ); | ||
remove_filter( $filter, array( get_called_class(), $hook ), $priority, 99 ); | ||
|
||
} | ||
|
||
/** | ||
* @param string $property_name | ||
* | ||
* @return bool | ||
*/ | ||
function __isset( $property_name ) { | ||
|
||
$save_trigger_error = $this->_trigger_error; | ||
$this->_trigger_error = false; | ||
|
||
do { // Use do{}while(false) to allow 'break'ing out of a code sequence. | ||
|
||
|
||
if ( ! is_callable( array( $this, $property_name ) ) ) { | ||
|
||
$isset = false; | ||
break; | ||
|
||
} | ||
|
||
if ( null === $this->$property_name() ) { | ||
|
||
$isset = false; | ||
break; | ||
|
||
} | ||
|
||
$isset = true; | ||
|
||
} while ( false ); | ||
|
||
$this->_trigger_error = $save_trigger_error; | ||
|
||
return $isset; | ||
|
||
} | ||
|
||
/** | ||
* | ||
* Call same named method to access virtial properties defined as methods. | ||
* | ||
* Generates debugging error message for attempts to get a non-existent property. | ||
* | ||
* @example | ||
* | ||
* $name = $this->name; // If no 'name' property, calls `name()` if that method exists. | ||
* | ||
* @param string $property_name | ||
* | ||
* @return null | ||
*/ | ||
function __get( $property_name ) { | ||
|
||
$value = null; | ||
|
||
if ( is_callable( $callable = array( $this, $property_name ) ) ) { | ||
|
||
$value = call_user_func( $callable ); | ||
|
||
} else if ( $this->_trigger_error ) { | ||
|
||
$message = __( "Cannot access property '%s' in class '%s'.", 'wplib' ); | ||
|
||
WPLib::trigger_error( sprintf( $message, $property_name, get_class( $this ) ) ); | ||
|
||
$value = null; | ||
|
||
} | ||
|
||
return $value; | ||
|
||
} | ||
|
||
/** | ||
* Generate debugging error message for attempts to set a non-existent property. | ||
* | ||
* @param string $property_name | ||
* @param mixed $value | ||
* | ||
* @return void | ||
*/ | ||
function __set( $property_name, $value ) { | ||
|
||
if ( is_callable( $callable = array( $this, "set_{$property_name}" ) ) ) { | ||
|
||
call_user_func( $callable, $value ); | ||
|
||
} else if ( $this->_trigger_error ) { | ||
|
||
$message = __( "Cannot set property '%s' in class '%s'.", 'wplib' ); | ||
|
||
WPLib::trigger_error( sprintf( $message, $property_name, get_class( $this ) ) ); | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* Generate debugging error message for attempts to call a non-existent method. | ||
* | ||
* @param string $method_name | ||
* @param array $args | ||
* | ||
* @return null | ||
*/ | ||
function __call( $method_name, $args ) { | ||
|
||
$value = null; | ||
|
||
if ( $this->_trigger_error ) { | ||
|
||
$message = __( "Cannot call method '%s' in class '%s'.", 'wplib' ); | ||
|
||
WPLib::trigger_error( sprintf( $message, $method_name, get_class( $this ) ) ); | ||
|
||
} | ||
|
||
return $value; | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to utilize a PHPDoc notation like WP does to indicate at what version a property, method, function or class was introduced. Example:
@since 1.3.0
.I also think we need to utilize a PHPDoc notation like WP does for indicating whether something is public or private (beyond prefixing with an underscore). Example:
@access private
.Additionally, as an open source project, we need to be adding the GPL notice to the top of each file.
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Need your help with figuring out out what to use.
Sure. I guess we are going to need to QA steps in the process for things like this.
WordPress does not do that and StackOverflow thinks we should not.
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I absolutely agree with the @SInCE it has come in handy many times in the past when working with legacy methods.
The way I handled that with PHPStorm was just to add
@since @@version
inSettings->Editor->File and Code Templates->Includes
For my specific instance I use @@Version because I build out with grunt and use grunt-replace to replace @@Version with the version i'm building with, but figured I would add my 2 cents :) 👍
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tripflex Nice idea. @wpscholar - thoughts?
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tripflex What was your use case for dynamically generating the version number? I'd be interested in learning more about your build workflow.
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally this is for when i'm deploying any WP plugins I create, and you can actually see one of the open source ones that I just started working on again:
https://github.com/tripflex/wp-login-flow
Specifically you can see in the Gruntfile.js the since replace:
https://github.com/tripflex/wp-login-flow/blob/master/Gruntfile.js#L271
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple reasons I like to have the @SInCE is one for any developers that build off my plugin with another plugin, theme, etc, and this way I know whenever i'm refactoring, updating, or changing things, what version those methods were implemented in. Because I also build off the core of WordPress there are many methods that depend on specific versions of WordPress.
With that in mind whenever I make updates and end up raising the min WordPress version I can go back and look at the last time I raised the min WordPress version, and then check those specific methods that were introduced in that version to hopefully prevent any conflicts or issues, or even make them backwards compatible
8dc27c3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tripflex Thanks for the details. I could see us implementing something like that as part of the workflow before tagging a new version of the library. cc @mikeschinkel