/** * Runs Codebench on the extending class. * * @return array benchmark output */ public function run() { // Array of all methods to loop over $methods = array_filter(get_class_methods($this), array($this, '_method_filter')); // Make sure the benchmark runs at least once, // also if no subject data has been provided. if (empty($this->subjects)) { $this->subjects = array('NULL' => NULL); } // Initialize benchmark output $codebench = array('class' => get_class($this), 'description' => $this->description, 'loops' => array('base' => (int) $this->loops, 'total' => (int) $this->loops * count($this->subjects) * count($methods)), 'subjects' => $this->subjects, 'benchmarks' => array()); // Benchmark each method foreach ($methods as $method) { // Initialize benchmark output for this method $codebench['benchmarks'][$method] = array('time' => 0, 'memory' => 0); // Using Reflection because simply calling $this->$method($subject) in the loop below // results in buggy benchmark times correlating to the length of the method name. $reflection = new ReflectioNamethod(get_class($this), $method); // Benchmark each subject on each method foreach ($this->subjects as $subject_key => $subject) { // Prerun each method/subject combo before the actual benchmark loop. // This way relatively expensive initial processes won't be benchmarked, e.g. autoloading. // At the same time we capture the return here so we don't have to do that in the loop anymore. $return = $reflection->invoke($this, $subject); // Start the timer for one subject $token = Profiler::start('codebench', $method . $subject_key); // The heavy work for ($i = 0; $i < $this->loops; ++$i) { $reflection->invoke($this, $subject); } // Stop and read the timer $benchmark = Profiler::total($token); // Benchmark output specific to the current method and subject $codebench['benchmarks'][$method]['subjects'][$subject_key] = array('return' => $return, 'time' => $benchmark[0], 'memory' => $benchmark[1]); // Update method totals $codebench['benchmarks'][$method]['time'] += $benchmark[0]; $codebench['benchmarks'][$method]['memory'] += $benchmark[1]; } } // Initialize the fastest and slowest benchmarks for both methods and subjects, time and memory, // these values will be overwritten using min() and max() later on. // The 999999999 values look like a hack, I know, but they work, // unless your method runs for more than 31 years or consumes over 1GB of memory. $fastest_method = $fastest_subject = array('time' => 999999999, 'memory' => 999999999); $slowest_method = $slowest_subject = array('time' => 0, 'memory' => 0); // Find the fastest and slowest benchmarks, needed for the percentage calculations foreach ($methods as $method) { // Update the fastest and slowest method benchmarks $fastest_method['time'] = min($fastest_method['time'], $codebench['benchmarks'][$method]['time']); $fastest_method['memory'] = min($fastest_method['memory'], $codebench['benchmarks'][$method]['memory']); $slowest_method['time'] = max($slowest_method['time'], $codebench['benchmarks'][$method]['time']); $slowest_method['memory'] = max($slowest_method['memory'], $codebench['benchmarks'][$method]['memory']); foreach ($this->subjects as $subject_key => $subject) { // Update the fastest and slowest subject benchmarks $fastest_subject['time'] = min($fastest_subject['time'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['time']); $fastest_subject['memory'] = min($fastest_subject['memory'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['memory']); $slowest_subject['time'] = max($slowest_subject['time'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['time']); $slowest_subject['memory'] = max($slowest_subject['memory'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['memory']); } } // Percentage calculations for methods foreach ($codebench['benchmarks'] as &$method) { // Calculate percentage difference relative to fastest and slowest methods $method['percent']['fastest']['time'] = $method['time'] / $fastest_method['time'] * 100; $method['percent']['fastest']['memory'] = $method['memory'] / $fastest_method['memory'] * 100; $method['percent']['slowest']['time'] = $method['time'] / $slowest_method['time'] * 100; $method['percent']['slowest']['memory'] = $method['memory'] / $slowest_method['memory'] * 100; // Assign a grade for time and memory to each method $method['grade']['time'] = $this->_grade($method['percent']['fastest']['time']); $method['grade']['memory'] = $this->_grade($method['percent']['fastest']['memory']); // Percentage calculations for subjects foreach ($method['subjects'] as &$subject) { // Calculate percentage difference relative to fastest and slowest subjects for this method $subject['percent']['fastest']['time'] = $subject['time'] / $fastest_subject['time'] * 100; $subject['percent']['fastest']['memory'] = $subject['memory'] / $fastest_subject['memory'] * 100; $subject['percent']['slowest']['time'] = $subject['time'] / $slowest_subject['time'] * 100; $subject['percent']['slowest']['memory'] = $subject['memory'] / $slowest_subject['memory'] * 100; // Assign a grade letter for time and memory to each subject $subject['grade']['time'] = $this->_grade($subject['percent']['fastest']['time']); $subject['grade']['memory'] = $this->_grade($subject['percent']['fastest']['memory']); } } return $codebench; }
/** * Executes all validation filters, rules, and callbacks. This should * typically be called within an if/else block. * * if ($validation->check()) * { * // The data is valid, do something here * } * * @return boolean */ public function check() { if (Kohana::$profiling === TRUE) { // Start a new benchmark $benchmark = Profiler::start('Validation', __FUNCTION__); } // New data set $data = $this->_errors = array(); // Assume nothing has been submitted $submitted = FALSE; // Get a list of the expected fields $expected = array_keys($this->_labels); // Import the filters, rules, and callbacks locally $filters = $this->_filters; $rules = $this->_rules; $callbacks = $this->_callbacks; foreach ($expected as $field) { if (isset($this[$field])) { // Some data has been submitted, continue validation $submitted = TRUE; // Use the submitted value $data[$field] = $this[$field]; } else { // No data exists for this field $data[$field] = NULL; } if (isset($filters[TRUE])) { if (!isset($filters[$field])) { // Initialize the filters for this field $filters[$field] = array(); } // Append the filters $filters[$field] += $filters[TRUE]; } if (isset($rules[TRUE])) { if (!isset($rules[$field])) { // Initialize the rules for this field $rules[$field] = array(); } // Append the rules $rules[$field] += $rules[TRUE]; } if (isset($callbacks[TRUE])) { if (!isset($callbacks[$field])) { // Initialize the callbacks for this field $callbacks[$field] = array(); } // Append the callbacks $callbacks[$field] += $callbacks[TRUE]; } } // Overload the current array with the new one $this->exchangeArray($data); if ($submitted === FALSE) { // Because no data was submitted, validation will not be forced return FALSE; } // Remove the filters, rules, and callbacks that apply to every field unset($filters[TRUE], $rules[TRUE], $callbacks[TRUE]); // Execute the filters foreach ($filters as $field => $set) { // Get the field value $value = $this[$field]; foreach ($set as $filter => $params) { // Add the field value to the parameters array_unshift($params, $value); if (strpos($filter, '::') === FALSE) { // Use a function call $function = new ReflectionFunction($filter); // Call $function($this[$field], $param, ...) with Reflection $value = $function->invokeArgs($params); } else { // Split the class and method of the rule list($class, $method) = explode('::', $filter, 2); // Use a static method call $method = new ReflectioNamethod($class, $method); // Call $Class::$method($this[$field], $param, ...) with Reflection $value = $method->invokeArgs(NULL, $params); } } // Set the filtered value $this[$field] = $value; } // Execute the rules foreach ($rules as $field => $set) { // Get the field value $value = $this[$field]; foreach ($set as $rule => $params) { if (!in_array($rule, $this->_empty_rules) and !Validate::not_empty($value)) { // Skip this rule for empty fields continue; } // Add the field value to the parameters array_unshift($params, $value); if (method_exists($this, $rule)) { // Use a method in this object $method = new ReflectioNamethod($this, $rule); if ($method->isStatic()) { // Call static::$rule($this[$field], $param, ...) with Reflection $passed = $method->invokeArgs(NULL, $params); } else { // Do not use Reflection here, the method may be protected $passed = call_user_func_array(array($this, $rule), $params); } } elseif (strpos($rule, '::') === FALSE) { // Use a function call $function = new ReflectionFunction($rule); // Call $function($this[$field], $param, ...) with Reflection $passed = $function->invokeArgs($params); } else { // Split the class and method of the rule list($class, $method) = explode('::', $rule, 2); // Use a static method call $method = new ReflectioNamethod($class, $method); // Call $Class::$method($this[$field], $param, ...) with Reflection $passed = $method->invokeArgs(NULL, $params); } if ($passed === FALSE) { // Remove the field name from the parameters array_shift($params); // Add the rule to the errors $this->error($field, $rule, $params); // This field has an error, stop executing rules break; } } } // Execute the callbacks foreach ($callbacks as $field => $set) { if (isset($this->_errors[$field])) { // Skip any field that already has an error continue; } foreach ($set as $callback) { if (is_string($callback) and strpos($callback, '::') !== FALSE) { // Make the static callback into an array $callback = explode('::', $callback, 2); } if (is_array($callback)) { // Separate the object and method list($object, $method) = $callback; // Use a method in the given object $method = new ReflectioNamethod($object, $method); if (!is_object($object)) { // The object must be NULL for static calls $object = NULL; } // Call $object->$method($this, $field, $errors) with Reflection $method->invoke($object, $this, $field); } else { // Use a function call $function = new ReflectionFunction($callback); // Call $function($this, $field, $errors) with Reflection $function->invoke($this, $field); } if (isset($this->_errors[$field])) { // An error was added, stop processing callbacks break; } } } if (isset($benchmark)) { // Stop benchmarking Profiler::stop($benchmark); } return empty($this->_errors); }