static var and functions: memory allocation in php - php

I have a doubt in memory allocation with a php 5.3 script.
Imagine you have 2 static classes (MyData and Test) like these:
class MyData {
private static $data = null;
public static function getData() {
if(self::$data == null)
self::$data = array(1,2,3,4,5,);
return self::$data;
}
}
class Test {
private static $test_data = null;
public static function getTestData1() {
if(self::$test_data==null) {
self::$test_data = MyData::getData();
self::$test_data[] = 6;
}
return self::$test_data;
}
public static function getTestData2() {
$test = MyData::getData();
$test[] = 6;
return $test;
}
}
And a simple test.php script:
for($i = 0; $i < 200000; $i++) {
echo "Pre-data1 Test:\n\t" . memory_get_usage(true) . "\n";
Test::getTestData1();
echo "Post-data1 Test:\n\t" . memory_get_usage(true) . "\n";
}
for($i = 0; $i < 200000; $i++) {
echo "Pre-data2 Test:\n\t" . memory_get_usage(true) . "\n";
Test::getTestData2();
echo "Post-data2 Test:\n\t" . memory_get_usage(true) . "\n";
}
I might suppose that the call to Test::getTestData1() will alloc memory for 2 static variables, while Test::getTestData2() will destroy $test (the copy of the static variable) on function return, so the second call is less "memory expensive".
But if I run the test.php script, memory_get_usage will show the same values for Test::getTestData1() and Test::getTestData2()
Why?

You are testing memory usage in the wrong way.
use memory_get_usage(false); to get the memory that is actually used by the script.
memory_get_usage(true); simply returns the memory allocated by System and this will always be the same for small scripts.

Related

PHP find median using heap vs sort

I was looking for a quick way to calculate the median of a list of numbers and came across this:
function array_median($array) {
// perhaps all non numeric values should filtered out of $array here?
$iCount = count($array);
if ($iCount == 0) {
return null;
}
// if we're down here it must mean $array
// has at least 1 item in the array.
$middle_index = floor($iCount / 2);
sort($array, SORT_NUMERIC);
$median = $array[$middle_index]; // assume an odd # of items
// Handle the even case by averaging the middle 2 items
if ($iCount % 2 == 0) {
$median = ($median + $array[$middle_index - 1]) / 2;
}
return $median;
}
This approach using sort() makes sense and is certainly the obvious approach. However, I was curious if a median heap would be faster. What was surprising was that when I implemented a simple median heap it is consistently significantly slower than the above method.
My simple MedianHeap class:
class MedianHeap{
private $lowerHeap;
private $higherHeap;
private $numbers = [];
public function __construct($numbers = null)
{
$this->lowerHeap = new SplMaxHeap();
$this->higherHeap = new SplMinHeap();
if (count($numbers)) {
$this->insertArray($numbers);
}
}
public function insertArray ($numbers) {
foreach($numbers as $number) {
$this->insert($number);
}
}
public function insert($number)
{
$this->numbers[] = $number;
if ($this->lowerHeap->count() == 0 || $number < $this->lowerHeap->top()) {
$this->lowerHeap->insert($number);
} else {
$this->higherHeap->insert($number);
}
$this->balance();
}
protected function balance()
{
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() - $smallerHeap->count() >= 2) {
$smallerHeap->insert($biggerHeap->extract());
}
}
public function getMedian()
{
if (!count($this->numbers)) {
return null;
}
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() == $smallerHeap->count()) {
return ($biggerHeap->top() + $smallerHeap->top())/2;
} else {
return $biggerHeap->top();
}
}
}
And then the code to benchmark:
$array = [];
for($i=0; $i<100000; $i++) {
$array[] = mt_rand(1,100000) / mt_rand(1,10000);
}
$t = microtime(true);
echo array_median($array);
echo PHP_EOL . 'Sort Median: ' . (microtime(true) - $t) . ' seconds';
echo PHP_EOL;
$t = microtime(true);
$list = new MedianHeap($array);
echo $list->getMedian();
echo PHP_EOL . 'Heap Median: '. (microtime(true) - $t) . ' seconds';
Is there something in PHP that makes using heaps for this inefficient somehow or is there something wrong with my implemenation?

memory_get_usage() & microtime()

Good day! I have this code:
final class bench
{
protected static $start_time;
protected static $start_memory;
public static function start()
{
self::$start_time = microtime(true);
self::$start_memory = memory_get_usage(true)/1024;
}
public static function finish()
{
echo PHP_EOL.'+'.round(memory_get_usage(true)/1024 - self::$start_memory, 3).' Kb load';
echo PHP_EOL.'+'.round(microtime(true) - self::$start_time, 3).' Time.';
}
}
But when I wanna use this little code here:
bench::start();
$array = ['f', 'g', 'f', 'd', 'ff'];
foreach($array as $key=>$value)
{
echo $key.'f'.$value;
}
bench::finish();
I am getting bad results. It is saying me +0 Kb load +0 Time.
So I tried to use this example:
$start = memory_get_usage()/1024 . "\n";
for ($i = 1; $i <= 100; $i++) {
echo $i;
}
echo '<br/>+'.round(memory_get_usage()/1024 - $start, 3).' Kb load';
And then I got normal results. Why so? Probably, there is something better than the code above
Your code is working. The memory used is a few bytes ; since round the division to 3 digits, 0kb is displayed.

Memoizing fibonacci function in php

I've created a memoized function of the recursive version of fibonacci.
I use this as an example for other kinds of functions that would use memoization.
My implementation is bad since if I include it in a library, that means that the global variable is still seen..
This is the original recursive fibonacci function:
function fibonacci($n) {
if($n > 1) {
return fibonacci($n-1) + fibonacci($n-2);
}
return $n;
}
and I modified it to a memoized version:
$memo = array();
function fibonacciMemo($n) {
global $memo;
if(array_key_exists($n, $memo)) {
return $memo[$n];
}
else {
if($n > 1) {
$result = fibonacciMemo($n-1) + fibonacciMemo($n-2);
$memo[$n] = $result;
return $result;
}
return $n;
}
}
I purposely didn't use the iterative method in implementing fibonacci.
Is there any better ways to memoize fibonacci function in php? Can you suggest me better improvements? I've seen func_get_args() and call_user_func_array as another way but I can't seem to know what is better?
So my main question is: How can I memoize fibonacci function in php properly? or What is the best way in memoizing fibonacci function in php?
Well, Edd Mann shows an excellent way to implement a memoize function in php in His post
Here is the example code (actually taken from Edd Mann's post):
$memoize = function($func)
{
return function() use ($func)
{
static $cache = [];
$args = func_get_args();
$key = md5(serialize($args));
if ( ! isset($cache[$key])) {
$cache[$key] = call_user_func_array($func, $args);
}
return $cache[$key];
};
};
$fibonacci = $memoize(function($n) use (&$fibonacci)
{
return ($n < 2) ? $n : $fibonacci($n - 1) + $fibonacci($n - 2);
});
Notice that the global definition it's replaced thanks to function clousure and PHP's first-class function support.
Other solution:
You can create a class containing as static members: fibonnacciMemo and $memo. Notice that you don't longer have to use $memo as a global variable, so it won't give any conflict with other namespaces.
Here is the example:
class Fib{
//$memo and fibonacciMemo are static members
static $memo = array();
static function fibonacciMemo($n) {
if(array_key_exists($n, static::$memo)) {
return static::$memo[$n];
}
else {
if($n > 1) {
$result = static::fibonacciMemo($n-1) + static::fibonacciMemo($n-2);
static::$memo[$n] = $result;
return $result;
}
return $n;
}
}
}
//Using the same method by Edd Mann to benchmark
//the results
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000249
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000016 (now with memoized fibonacci)
//Cleaning $memo
Fib::$memo = array();
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000203 (after 'cleaning' $memo)
Using this, you avoid the use of global and also the problem of cleaning the cache. Althought, $memo is not thread save and the keys stored are no hashed values.
Anyways, you can use all the php memoize utilites such as memoize-php
i think... this should to to memoize a fibonacci:
function fib($n, &$computed = array(0,1)) {
if (!array_key_exists($n,$computed)) {
$computed[$n] = fib($n-1, $computed) + fib($n-2, $computed);
}
return $computed[$n];
}
some test
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000068
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000005
//Cleaning $arr
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000039
Another solution:
function fib($n, &$memo = []) {
if (array_key_exists($n,$memo)) {
return $memo[$n];
}
if ($n <=2 ){
return 1;
}
$memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
return $memo[$n];
}
Performance:
$start = microtime(true);
fib(100);
echo sprintf("%f\n", microtime(true) - $start);
// 0.000041
This's an implementation of memoize a fibonacci:
function fib(int $n, array &$memo = [0,1,1]) : float {
return $memo[$n] ?? $memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
}
Call
echo fib(20); // 6765
function fibMemo($n)
{
static $cache = [];
//print_r($cache);
if (!empty($cache[$n])) {
return $cache[$n];
} else {
if ($n < 2) {
return $n;
} else {
$p = fibMemo($n - 1) + fibMemo($n - 2);
$cache[$n] = $p;
return $p;
}
}
}
echo fibMemo(250);

PHP average calculator not displaying results properly

I'm creating a php calculator that needs to use the following classes, then print off the users name and the average score they achieved. This is the code I have so far, but it's not displaying correctly, it's saying there are missing arguments and undefined variables but i'm not sure where i've gone wrong!
<?php
class person {
public $name;
}
class student extends person {
function student ($name, $grade1, $grade2) {
if(is_numeric($grade1) && is_numeric($grade2)){
$grades = array($grade1, $grade2);
}
elseif (is_numeric($grade1)) {
$grade2 = 0;
}
else {
$grade1 = 0;
}
}
function average ($grades) {
$length = count($grades);
$total = 0;
for ($i = 0; $i < $length; $i++) {
$total = $total + $grades[i];
}
$average = $total / $length;
return $average;
}
}
$person1 = new student ($_POST['firstName'], $_POST['firstGrade1'], $_POST['firstGrade2']);
$person2 = new student ($_POST['secondName'], $_POST['secondGrade1'], $_POST['secondGrade2']);
$person3 = new student ($_POST['thirdName'], $_POST['thirdGrade1'], $_POST['thirdGrade2']);
echo "<br/> $person1->name" . "achieved an average of" . "$person1->average();";
echo "<br/> $person2->name" . "achieved an average of" . "$person2->average();";
echo "<br/> $person3->name" . "achieved an average of" . "$person3->average();";
?>
ERROR MESSAGES:
Warning: Missing argument 1 for student::average(), called in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\my portable files\Exercise 4\average.php on line 40 and defined in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\my portable files\Exercise 4\average.php on line 22
Notice: Undefined variable: grades in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\my portable files\Exercise 4\average.php on line 23
Warning: Division by zero in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\my portable files\Exercise 4\average.php on line 30
You don't appear to be returning that $grades variable. It's probably not defined because you aren't returning anything.
Your method:
function student ($name, $grade1, $grade2) {
if(is_numeric($grade1) && is_numeric($grade2)){
$grades = array($grade1, $grade2);
}
elseif (is_numeric($grade1)) {
$grade2 = 0;
$grades = array($grade1, $grade2);
}
else {
$grade1 = 0;
$grades = array($grade1, $grade2);
}
return $grades
}
Will need to look more like that. You'll also want to actually add grade1 and grad2 to your returned array in your alternate conditions.
The following is the classes enhanced. You will notice that they have constructors and functions to request variables. Private variables are usually the preferred method as they are protected and therefore cannot be modified outside the class.
class person {
private $name = "";
public function __construct ($nameV) {
$this->name = $nameV;
}
public function getName() {
return $this->name;
}
}
class student extends person {
private $grades;
public function __construct ($name, $grade1, $grade2) {
parent::__construct($name);
if ( ! is_numeric($grade1)) { $grade1 = 0; }
if ( ! is_numeric($grade2)) { $grade2 = 0; }
$this->grades = array($grade1, $grade2);
}
public function average () {
$length = count($this->grades);
$total = 0;
for ($i = 0; $i < $length; $i++) {
$total = $total + $this->grades[$i];
}
$average = $total / $length;
return $average;
}
}
The export code is then simply:
echo "<br/>" . $person1->getName() . " achieved an average of " . $person1->average();
echo "<br/>" . $person2->getName() . " achieved an average of " . $person2->average();
echo "<br/>" . $person3->getName() . " achieved an average of " . $person3->average();
Due to not having the form, I tested with the following data:
$person1 = new student ("XYZ", 1, 2);
$person2 = new student ("XYZ2", 100, 20);
$person3 = new student ("XYZ3", 95, 94);
Which exported:
XYZ achieved an average of 1.5
XYZ2 achieved an average of 60
XYZ3 achieved an average of 94.5

Calling a function within a class

I am having trouble calling a specific function within a class. The call is made:
case "Mod10":
if (!validateCreditCard($fields[$field_name]))
$errors[] = $error_message;
break;
and the class code is:
class CreditCardValidationSolution {
var $CCVSNumber = '';
var $CCVSNumberLeft = '';
var $CCVSNumberRight = '';
var $CCVSType = '';
var $CCVSError = '';
function validateCreditCard($Number) {
$this->CCVSNumber = '';
$this->CCVSNumberLeft = '';
$this->CCVSNumberRight = '';
$this->CCVSType = '';
$this->CCVSError = '';
// Catch malformed input.
if (empty($Number) || !is_string($Number)) {
$this->CCVSError = $CCVSErrNumberString;
return FALSE;
}
// Ensure number doesn't overrun.
$Number = substr($Number, 0, 20);
// Remove non-numeric characters.
$this->CCVSNumber = preg_replace('/[^0-9]/', '', $Number);
// Set up variables.
$this->CCVSNumberLeft = substr($this->CCVSNumber, 0, 4);
$this->CCVSNumberRight = substr($this->CCVSNumber, -4);
$NumberLength = strlen($this->CCVSNumber);
$DoChecksum = 'Y';
// Mod10 checksum process...
if ($DoChecksum == 'Y') {
$Checksum = 0;
// Add even digits in even length strings or odd digits in odd length strings.
for ($Location = 1 - ($NumberLength % 2); $Location < $NumberLength; $Location += 2) {
$Checksum += substr($this->CCVSNumber, $Location, 1);
}
// Analyze odd digits in even length strings or even digits in odd length strings.
for ($Location = ($NumberLength % 2); $Location < $NumberLength; $Location += 2) {
$Digit = substr($this->CCVSNumber, $Location, 1) * 2;
if ($Digit < 10) {
$Checksum += $Digit;
} else {
$Checksum += $Digit - 9;
}
}
// Checksums not divisible by 10 are bad.
if ($Checksum % 10 != 0) {
$this->CCVSError = $CCVSErrChecksum;
return FALSE;
}
}
return TRUE;
}
}
When I run the application - I get the following message:
Fatal error: Call to undefined
function validateCreditCard() in
C:\xampp\htdocs\validation.php
on line 339
any ideas?
class Foo {
// How may I be called?
function bar() {
}
function baz() {
// Use $this-> to call methods within the same instance
$this->bar();
}
function eek() {
// Use self:: to call a function within the same class statically
self::bar();
}
}
// Use [class]:: to call a class function statically
Foo::bar();
// Use [object]-> to call methods of objects
$fooInstance = new Foo();
$fooInstance->bar();
Calling methods statically or as an instance method is not necessarily interchangeable, beware. That's all pretty well covered in the basics of OOP by the way.
Does the class containing the function within which you use the Switch-Case inherit the CreditCardValidationSolution Class....??
My guess would be that you are trying to call the function outside the class without inheriting it.... Maybe you just missed it....
Edit After Reading Comment :
What you need here is "Inheritance"
Take a look at the following links.....
http://www.killerphp.com/tutorials/object-oriented-php/php-objects-page-4.php
http://marakana.com/blog/examples/php-inheritance.html
Hope this helps....

Categories