Start a new Kumite
AllAgda (Beta)BF (Beta)CCFML (Beta)ClojureCOBOL (Beta)CoffeeScriptCommonLisp (Beta)CoqC++CrystalC#D (Beta)DartElixirElm (Beta)Erlang (Beta)Factor (Beta)Forth (Beta)Fortran (Beta)F#GoGroovyHaskellHaxe (Beta)Idris (Beta)JavaJavaScriptJulia (Beta)Kotlinλ Calculus (Beta)LeanLuaNASMNim (Beta)Objective-C (Beta)OCaml (Beta)Pascal (Beta)Perl (Beta)PHPPowerShell (Beta)Prolog (Beta)PureScript (Beta)PythonR (Beta)RacketRaku (Beta)Reason (Beta)RISC-V (Beta)RubyRustScalaShellSolidity (Beta)SQLSwiftTypeScriptVB (Beta)
Show only mine

Kumite (ko͞omiˌtā) is the practice of taking techniques learned from Kata and applying them through the act of freestyle sparring.

You can create a new kumite by providing some initial code and optionally some test cases. From there other warriors can spar with you, by enhancing, refactoring and translating your code. There is no limit to how many warriors you can spar with.

A great use for kumite is to begin an idea for a kata as one. You can collaborate with other code warriors until you have it right, then you can convert it to a kata.

Ad
Ad

Kata in PHP #7 - Recursion #2 - Fibonacci

Kata

Recursion #2 - Fibonacci (7kyu)

function fibonacci($n) {
  return $n === 1 || $n === 2 ? 1 : fibonacci($n - 1) + fibonacci($n - 2);
}



$test->describe('fibonacci($n)', function () {
  $GLOBALS['test']->it('should work for some fixed tests', function () {
    $GLOBALS['test']->assert_equals(fibonacci(1), 1);
    $GLOBALS['test']->assert_equals(fibonacci(2), 1);
    $GLOBALS['test']->assert_equals(fibonacci(3), 2);
    $GLOBALS['test']->assert_equals(fibonacci(4), 3);
    $GLOBALS['test']->assert_equals(fibonacci(5), 5);
    $GLOBALS['test']->assert_equals(fibonacci(6), 8);
    $GLOBALS['test']->assert_equals(fibonacci(7), 13);
    $GLOBALS['test']->assert_equals(fibonacci(8), 21);
    $GLOBALS['test']->assert_equals(fibonacci(9), 34);
    $GLOBALS['test']->assert_equals(fibonacci(10), 55);
    $GLOBALS['test']->assert_equals(fibonacci(11), 89);
    $GLOBALS['test']->assert_equals(fibonacci(12), 144);
    $GLOBALS['test']->assert_equals(fibonacci(13), 233);
    $GLOBALS['test']->assert_equals(fibonacci(14), 377);
    $GLOBALS['test']->assert_equals(fibonacci(15), 610);
    $GLOBALS['test']->assert_equals(fibonacci(16), 987);
    $GLOBALS['test']->assert_equals(fibonacci(17), 1597);
    $GLOBALS['test']->assert_equals(fibonacci(18), 2584);
    $GLOBALS['test']->assert_equals(fibonacci(19), 4181);
    $GLOBALS['test']->assert_equals(fibonacci(20), 6765);
  });
});

Kata in PHP #8 - Training JS #36: methods of Math---kata author's lover:random()

Kata

Training JS #36: methods of Math---kata author's lover:random() (7kyu)

function rnd_code() {
  $result = "";
  $upcase = str_split("ABCDEFGHIJKLM");
  $symbols = str_split("~!@#$%^&*");
  for ($i = 0; $i < 2; $i++) {
    $result .= $upcase[~~(lcg_value() * count($upcase))];
  }
  for ($i = 0; $i < 4; $i++) {
    $result .= ~~(10 * lcg_value());
  }
  for ($i = 0; $i < 2; $i++) {
    $result .= $symbols[~~(lcg_value() * count($symbols))];
  }
  return $result;
}



$test->describe('The \'rnd_code\' function', function () {
  $GLOBALS['test']->it("should work for a basic test", function () {
    $yourcode = rnd_code();
    echo "Your Code: $yourcode<br />";
    $GLOBALS['test']->expect(is_string($yourcode), "The result should be string");
    $GLOBALS['test']->expect(strlen($yourcode) === 8, "The length should be 8");
    $yourcode = str_split($yourcode);
    $GLOBALS['test']->expect(array_search($yourcode[0], str_split("ABCDEFGHIJKLM")) !== false, "1st char should generate from A-M");
    $GLOBALS['test']->expect(array_search($yourcode[1], str_split("ABCDEFGHIJKLM")) !== false, "2nd char should generate from A-M");
    $GLOBALS['test']->expect(array_search($yourcode[2], str_split("0123456789")) !== false, "3rd char should generate from 0-9");
    $GLOBALS['test']->expect(array_search($yourcode[3], str_split("0123456789")) !== false, "4th char should generate from 0-9");
    $GLOBALS['test']->expect(array_search($yourcode[4], str_split("0123456789")) !== false, "5th char should generate from 0-9");
    $GLOBALS['test']->expect(array_search($yourcode[5], str_split("0123456789")) !== false, "6th char should generate from 0-9");
    $GLOBALS['test']->expect(array_search($yourcode[6], str_split("~!@#$%^&*")) !== false, "7th char should generate from ~!@#$%^&*");
    $GLOBALS['test']->expect(array_search($yourcode[7], str_split("~!@#$%^&*")) !== false, "8th char should generate from ~!@#$%^&*");
  });
  $GLOBALS['test']->it('should work for 100 random tests', function () {
    $codes = [];
    for ($i = 0; $i < 100; $i++) {
      array_push($codes, rnd_code());
    }
    for ($i = 0; $i < 100; $i++) {
      for ($k = 0; $k < $i; $k++) {
        $GLOBALS['test']->assert_not_equals($codes[$i], $codes[$k], "Your function should not generate duplicate verification codes");
      }
    }
  });
});

Kata in PHP #9 - Genetic Algorithm Series - #1 Generate

Kata

Genetic Algorithm Series - #1 Generate (7kyu)

function generate($length) {
  $chromosome = "";
  for ($i = 0; $i < $length; $i++) {
    $chromosome .= round(lcg_value());
  }
  return $chromosome;
}



$test->describe("The chromosome generator", function () {
  global $test;
  $test->it("should respect the given length", function () {
    global $test;
    $test->assert_equals(strlen(generate(0)), 0);
    $test->assert_equals(strlen(generate(1)), 1);
    $test->assert_equals(strlen(generate(8)), 8);
    $test->assert_equals(strlen(generate(16)), 16);
    $test->assert_equals(strlen(generate(32)), 32);
    $test->assert_equals(strlen(generate(64)), 64);
    $test->assert_equals(strlen(generate(256)), 256);
  });
  $test->it("should probably produce chromosomes with at least 1 '1' and at least 1 '0' for length 50", function () {
    global $test;
    $chromosome = generate(50);
    echo "Your Chromosome: $chromosome<br />";
    $test->expect(preg_match('/0/', $chromosome), "Your chromosome did not contain a single '0'");
    $test->expect(preg_match('/1/', $chromosome), "Your chromosome did not contain a single '1'");
  });
  $test->it("should probably return all possible chromosomes of length 5 when run 20000 times", function () {
    global $test;
    $chromosomes = [];
    for ($i = 0; $i < 20000; $i++) {
      array_push($chromosomes, generate(5));
    }
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00000';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00001';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00010';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00011';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00100';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00101';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00110';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '00111';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01000';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01001';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01010';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01011';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01100';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01101';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01110';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '01111';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10000';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10001';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10010';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10011';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10100';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10101';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10110';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '10111';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11000';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11001';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11010';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11011';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11100';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11101';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11110';})) >= 1);
    $test->expect(count(array_filter($chromosomes, function ($c) {return $c === '11111';})) >= 1);
  });
});

Kata in PHP #10 - Genetic Algorithm Series - #2 Mutation

Kata

Genetic Algorithm Series - #2 Mutation (7kyu)

function mutate($chromosome, $probability) {
  return implode(array_map(function ($d, $p) {
    return lcg_value() < $p ? ($d === '0' ? '1' : '0') : $d;
  }, str_split($chromosome), array_fill(0, strlen($chromosome), $probability)));
}



$test->describe("The chromosome mutating function", function () {
  global $test;
  $test->it("should convert all '0's to '1's and vice versa when the mutation probability is 1 (100%)", function () {
    global $test;
    $test->assert_equals(mutate('0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 1), '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111');
    $test->assert_equals(mutate('1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', 1), '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
  });
  $test->it("should not mutate the chromosome at all when the probability is 0", function () {
    global $test;
    $test->assert_equals(mutate('0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 0), '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
    $test->assert_equals(mutate('1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', 0), '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111');
  });
  $test->it('should mutate about 50% of the chromosome when the mutation probability is 0.5 (50%)', function () {
    global $test;
    $all_zeroes = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
    $all_ones = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
    $mutated = mutate($all_zeroes, 0.5);
    $test->expect(count(array_filter(str_split($mutated), function ($d) {return $d === '0';})) >= 35 && count(array_filter(str_split($mutated), function ($d) {return $d === '0';})) <= 65);
    $test->expect(count(array_filter(str_split($mutated), function ($d) {return $d === '1';})) >= 35 && count(array_filter(str_split($mutated), function ($d) {return $d === '1';})) <= 65);
    $mutated = mutate($all_ones, 0.5);
    $test->expect(count(array_filter(str_split($mutated), function ($d) {return $d === '0';})) >= 35 && count(array_filter(str_split($mutated), function ($d) {return $d === '0';})) <= 65);
    $test->expect(count(array_filter(str_split($mutated), function ($d) {return $d === '1';})) >= 35 && count(array_filter(str_split($mutated), function ($d) {return $d === '1';})) <= 65);
  });
  $test->it("should work properly for random mutation probabilities", function () {
    global $test;
    for ($i = 0; $i < 5; $i++) {
      echo "Testing a mutation probability of " . ($p = lcg_value()) . "<br />";
      echo "Your mutated chromosome: " . ($mutated = mutate('0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', $p)) . "<br />";
      $test->expect(preg_match('/0/', $mutated));
      $test->expect(preg_match('/1/', $mutated));
    }
  });
});

Kata in PHP #11 - Genetic Algorithm Series - #3 Crossover

Kata

Genetic Algorithm Series - #3 Crossover (7kyu)

function crossover($chromosome1, $chromosome2, $index) {
  $new_chromosome1 = [];
  for ($i = 0; $i < $index; $i++) {
    array_push($new_chromosome1, str_split($chromosome1)[$i]);
  }
  for ($i = $index; $i < strlen($chromosome1); $i++) {
    array_push($new_chromosome1, str_split($chromosome2)[$i]);
  }
  $new_chromosome2 = [];
  for ($i = 0; $i < $index; $i++) {
    array_push($new_chromosome2, str_split($chromosome2)[$i]);
  }
  for ($i = $index; $i < strlen($chromosome2); $i++) {
    array_push($new_chromosome2, str_split($chromosome1)[$i]);
  }
  return [implode($new_chromosome1), implode($new_chromosome2)];
}



$test->describe("The chromosome crossover function", function () {
  global $test;
  $test->it("should work for the example in the description", function () {
    global $test;
    $test->assert_similar(crossover('111000', '000110', 3), ['111110', '000000']);
  });
  $test->it("should work for basic tests", function () {
    global $test;
    $test->assert_similar(crossover('', '', 0), ['', '']);
    $test->assert_similar(crossover('01', '10', 1), ['00', '11']);
    $test->assert_similar(crossover('00000000', '11111111', 0), ['11111111', '00000000']);
    $test->assert_similar(crossover('00000000', '11111111', 7), ['00000001', '11111110']);
  });
  $test->it("should work for more fixed tests", function () {
    global $test;
    $test->assert_similar(crossover('0000', '1111', 0), ['1111', '0000']);
    $test->assert_similar(crossover('0000', '1111', 1), ['0111', '1000']);
    $test->assert_similar(crossover('0000', '1111', 2), ['0011', '1100']);
    $test->assert_similar(crossover('0000', '1111', 3), ['0001', '1110']);
    $test->assert_similar(crossover('0000', '1111', 4), ['0000', '1111']);
    $test->assert_similar(crossover('0010011110', '1110010100', 3), ['0010010100', '1110011110']);
    $test->assert_similar(crossover('0010011110', '1110010100', 7), ['0010011100', '1110010110']);
  });
});

Kata in PHP #12 - Genetic Algorithm Series - #4 Get population and fitnesses

Kata

Genetic Algorithm Series - #4 Get population and fitnesses (Beta)

function map_population_fit($population, $fitness) {
  return array_map(function ($chromosome, $formula) {
    return ["chromosome" => $chromosome, "fitness" => $formula($chromosome)];
  }, $population, array_fill(0, count($population), $fitness));
}



$test->describe('map_population_fit($population, $fitness)', function () {
  global $test;
  $test->it("should return an array of the correct format and with the correct entries for the given population", function () {
    global $test;
    $population = ['10100111', '11011100',
    '01101000', '01100111', '01000010', '10001001', '10111100', '11111000', '11001100',
    '00001011', '01011011', '01000111', '11010101', '00101101', '00100111', '00000111',
    '00101000', '00101011', '01011011', '10100001', '00111000', '00010110', '00101100',
    '11111110', '10101001', '11101001', '00011001', '10100011', '11000001', '11010101',
    '11000110', '01111000', '11011000', '00111010', '11110100', '00100111', '10001101',
    '11000100', '01110010', '10011111', '10110101', '11001100', '00110111', '00000100',
    '10010010', '00011000', '10111010', '10001000', '00010011', '01001011', '00100010',
    '01111000', '01110111', '11101011', '00001010', '00000000', '01100011', '00011111',
    '10000001', '01100010', '11011100', '10001100', '01110010', '11011011', '00000111',
    '10100100', '00101101', '00001101', '10010110', '10101110', '00111010', '00011001',
    '11000110', '01010101', '00101000', '00000110', '11001000', '11000110', '01010100',
    '01011010', '00101101', '00011001', '00010101', '10101110', '01100010', '01110101',
    '01111011', '00111000', '11101110', '00110100', '11100100', '01011101', '10000110',
    '11111101', '11000001', '11000111', '11000111', '01011000', '10011011', '10110101'];
    function fitness($c) {
      $ideal = '10011001';
      $r = 0;
      for ($i = 0; $i < strlen($c); $i++) {
        if (str_split($c)[$i] === str_split($ideal)[$i]) $r++;
      }
      return $r / strlen($ideal);
    }
    $actual = map_population_fit($population, 'fitness');
    for ($i = 0; $i < count($population); $i++) {
      $test->assert_similar($actual[$i], ["chromosome" => $population[$i], "fitness" => fitness($population[$i])]);
    }
  });
});

Kata in PHP #13 - Genetic Algorithm Series - #5 Roulette wheel selection

Kata

Genetic Algorithm Series - #5 Roulette wheel selection (6kyu)

Side Note

Guess what my next "Kata in PHP" Kumite might be about ;)

function select($population, $fitnesses) {
  $sum_fitnesses = array_reduce($fitnesses, function ($sum, $fitness) {
    return $sum + $fitness;
  }, 0);
  $i = 0;
  $k = 0;
  while (true) {
    $rand = lcg_value();
    if ($rand < $fitnesses[$i % count($fitnesses)] / $sum_fitnesses && $k >= 33) {
      return $population[$i % count($population)];
    } else if ($rand < $fitnesses[$i % count($fitnesses)] / $sum_fitnesses) {
      $k++;
    }
    $i++;
  }
}



$test->describe('select($population, $fitnesses)', function () {
  global $test;
  $test->it("should return the correct proportion for each 'chromosome' according to their relative fitnesses", function () {
    global $test;
    $population = [1, 2, 3, 4];
    $fitnesses = [0.01, 0.01, 0.01, 0.01];
    $selection = [];
    for ($i = 0; $i < 1000; $i++) {
      array_push($selection, select($population, $fitnesses));
    }
    $ones = count(array_filter($selection, function ($c) {
      return $c === 1;
    }));
    $twos = count(array_filter($selection, function ($c) {
      return $c === 2;
    }));
    $threes = count(array_filter($selection, function ($c) {
      return $c === 3;
    }));
    $fours = count(array_filter($selection, function ($c) {
      return $c === 4;
    }));
    $test->expect($ones >= 200 && $ones <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($twos >= 200 && $twos <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($threes >= 200 && $threes <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($fours >= 200 && $fours <= 300, "Your probability is more than 5% off in 1000 runs");
    $population = [1, 2, 3];
    $fitnesses = [0.5, 0.5, 1];
    $selection = [];
    for ($i = 0; $i < 1000; $i++) {
      array_push($selection, select($population, $fitnesses));
    }
    $ones = count(array_filter($selection, function ($c) {
      return $c === 1;
    }));
    $twos = count(array_filter($selection, function ($c) {
      return $c === 2;
    }));
    $threes = count(array_filter($selection, function ($c) {
      return $c === 3;
    }));
    $test->expect($ones >= 200 && $ones <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($twos >= 200 && $twos <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($threes >= 450 && $threes <= 550, "Your probability is more than 5% off in 1000 runs");
    $population = [1, 2, 3];
    $fitnesses = [0.0001, 0.0001, 0.0002];
    $selection = [];
    for ($i = 0; $i < 1000; $i++) {
      array_push($selection, select($population, $fitnesses));
    }
    $ones = count(array_filter($selection, function ($c) {
      return $c === 1;
    }));
    $twos = count(array_filter($selection, function ($c) {
      return $c === 2;
    }));
    $threes = count(array_filter($selection, function ($c) {
      return $c === 3;
    }));
    $test->expect($ones >= 200 && $ones <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($twos >= 200 && $twos <= 300, "Your probability is more than 5% off in 1000 runs");
    $test->expect($threes >= 450 && $threes <= 550, "Your probability is more than 5% off in 1000 runs");
    $population = [1, 2, 3, 4];
    $fitnesses = [0.8, 0.6, 0.4, 0.2];
    $selection = [];
    for ($i = 0; $i < 1000; $i++) {
      array_push($selection, select($population, $fitnesses));
    }
    $ones = count(array_filter($selection, function ($c) {
      return $c === 1;
    }));
    $twos = count(array_filter($selection, function ($c) {
      return $c === 2;
    }));
    $threes = count(array_filter($selection, function ($c) {
      return $c === 3;
    }));
    $fours = count(array_filter($selection, function ($c) {
      return $c === 4;
    }));
    $test->expect($ones >= 350 && $ones <= 450);
    $test->expect($twos >= 250 && $twos <= 350);
    $test->expect($threes >= 150 && $threes <= 250);
    $test->expect($fours >= 50 && $fours <= 150);
    $population = [1, 2, 3, 4, 5];
    $fitnesses = [0.1, 0.4, 0, 0.3, 0.2];
    $selection = [];
    for ($i = 0; $i < 1000; $i++) {
      array_push($selection, select($population, $fitnesses));
    }
    $ones = count(array_filter($selection, function ($c) {
      return $c === 1;
    }));
    $twos = count(array_filter($selection, function ($c) {
      return $c === 2;
    }));
    $threes = count(array_filter($selection, function ($c) {
      return $c === 3;
    }));
    $fours = count(array_filter($selection, function ($c) {
      return $c === 4;
    }));
    $fives = count(array_filter($selection, function ($c) {
      return $c === 5;
    }));
    $test->expect($ones >= 50 && $ones <= 150);
    $test->expect($twos >= 350 && $twos <= 450);
    $test->expect($threes === 0, "For a chromosome of fitness 0, it should never be chosen");
    $test->expect($fours >= 250 && $fours <= 350);
    $test->expect($fives >= 150 && $fives <= 250);
  });
});

PHP Classes: public, private and protected

Overview and Background

A few weeks back when I was creating my custom PHP testing framework by defining a Test class, I realised that if my PHP testing framework were to be used to test the code of others (like here in Codewars or in Strive Qualified), I would have to ensure that certain class properties and methods cannot be directly accessed or modified by the user; otherwise, the user can hack the testing framework and cheat. Immediately, the first thought that came to my mind was the private keyword (which I believe Codecademy has taught (me) in its PHP course) as that keyword makes that particular property or method inaccessible outside the class. However, my original intent of my PHP testing framework was that other users should be able to effortlessly inherit from my Test class using the extends keyword and the child class should contain all the properties and functioning methods from the original Test class simply by inheriting. By making certain properties and methods used throughout the class private (instead of protected as I will explain later), inheritance from my Test class became impossible because the child class will not have inherited the key private properties and methods and therefore the child class (of Test) will not function properly. Therefore, after some research, I realised that private was not the correct keyword to use and protected should be used instead. But then, you may ask, "What is the difference between private and protected if they both prevent external access to the affected properties/methods?"

public

The public keyword is by far the most common keyword used when declaring or defining properties/methods in PHP classes. All properties/methods declared/defined with this keyword can be accessible throughout the entire PHP script being executed.

private

The private keyword ensures that the declared property/method can only be accessed within the very class in which it is defined (the advantage of private methods/properties). However, the major drawback of using private (if not used correctly) is that child classes cannot inherit such properties/methods at all.

protected

The protected keyword ensures that all properties/methods declared/defined using this keyword cannot be accessed externally. However, its main advantage over the "private" keyword is that such methods/properties can be inherited by child classes.

Code

The code shown to the right demonstrates the behaviour of properties declared according to the keywords mentioned above.

class ParentClass {
  // A public property
  public $public = "public";

  // A private property
  private $private = "private";

  // A protected property
  protected $protected = "protected";

  // Access the public property within the class
  public function echo_public() {
    echo $this->public;
  }

  // Access the private property within the class
  public function echo_private() {
    echo $this->private;
  }

  // Access the protected property within the class
  public function echo_protected() {
    echo $this->protected;
  }
}

class ChildClass extends ParentClass {
  // Let's try to do the same as in the parent class ...

  // Access the public property in the child class
  public function echo_public() {
    echo $this->public;
  }

  // Attempting to access the private property in the child class
  public function echo_private() {
    echo $this->private;
  }

  // Access the protected property in the child class
  public function echo_protected() {
    echo $this->protected;
  }
}

$test->describe("PHP Classes", function () {
  global $test;
  $test->it("All three of 'public', 'private' and 'protected' properties should be accessible within the class itself", function () {
    global $test, $obj;
    $obj = new ParentClass;
    $test->expect_no_error("An error should not be thrown", function () {
      global $obj;
      $obj->echo_public();
      echo "<br />";
    });
    $test->expect_no_error("An error should not be thrown", function () {
      global $obj;
      $obj->echo_private();
      echo "<br />";
    });
    $test->expect_no_error("An error should not be thrown", function () {
      global $obj;
      $obj->echo_protected();
      echo "<br />";
    });
  });
  $test->it("The child class should be able to access both the public and protected properties but not the private property", function () {
    global $test, $obj;
    $obj = new ChildClass;
    $obj->echo_public();
    echo "<br />";
    $test->expect(property_exists("ChildClass", "public"));
    $obj->echo_private();
    echo "<br />";
    $test->expect(!property_exists("ChildClass", "private"));
    $obj->echo_protected();
    echo "<br />";
    $test->expect(property_exists("ChildClass", "protected"));
  });
  $test->it("The public property should be accessible within the entire PHP script being executed but attempts to access private or protected properties externally should thrown an error", function () {
    global $test, $obj;
    $obj = new ParentClass;
    $test->expect_no_error("An error should not be thrown", function () {
      global $obj;
      echo "$obj->public<br />";
    });

    // NOTE: Somehow I cannot get my PHP testing framework to handle the fatal errors (caused by trying to access private/protected properties externally) properly but if you uncomment the code below you will see that it throws a fatal error.
    # echo $obj->private;
    # echo $obj->protected;
  });
});
Loops
Control Flow
Basic Language Features
Fundamentals
Arrays
Data Types

Simple example of loop types in bash:

  • for
  • while
  • until
#!/bin/bash
# some array
some_arr=('A', 'B', 'C')
# array length
len=${#some_arr[@]}

# for-in loop
echo "For In Loop"

for i in ${some_arr[*]}; do
  printf $i
done

# c-like for loop
echo -e "\nC-Like for Loop"

for((i=0;i<$len;i++)); do
  printf ${some_arr[$i]}
done;

# more c-like for loop
echo -e "\nMore C-like for loop"

for((i=0;i<$len;i++)) { 
  printf ${some_arr[i]}
}

# while loop
i=0
echo -e "\nWhile loop"

while [ $i -lt $len ]; do
  printf ${some_arr[$i]}
  let i+=1
done;

# until loop
j=0
echo -e "\nUntil loop"

until [ $j -ge $len ]; do
  printf ${some_arr[$j]}
  let j+=1
done

echo "THE END"
Interfaces
Basic Language Features
Object-oriented Programming
Fundamentals
Programming Paradigms

Interfaces in PHP - An Introduction

Overview

Interfaces are part of object-oriented PHP. Syntax-wise, interfaces look very similar to PHP Classes, the only difference being that interfaces are declared with an interface keyword instead of the class keyword:

interface MyInterface {
  // Interface code here
}

However, there are a few major differences between interfaces and classes in PHP:

  • In terms of inheritance, while a child class can only inherit from one parent class, a "child" interface can inherit from multiple interfaces
  • Content-wise, while a class can have any combination of public, private and protected properties and methods as well as class constants, an interface can only have interface constants and/or (abstract) public methods (I'll expand on this shortly)
  • An instance of a class (called an object) can be instantiated using the new keyword but it is impossible to create instances of interfaces
  • Methods are defined inside a class but methods are only declared in interfaces (i.e. you cannot say what a method does in an interface)

Why use interfaces?

Since you cannot directly create instances of interfaces and since there are lots of restrictions when creating interfaces, you may ask, "Why should we even bother with using interfaces if the same thing can be achieved using classes alone?"

Below are a few reasons why you should consider using interfaces along with classes especially if your (PHP) project involves more than one developer:

  1. When exactly 1 interface is used and when exactly 1 class implements the interface, the inclusion of the interface (with its declared but not defined public methods) ensures that the class will always contain all the public methods specified in the interface because PHP will throw an error if a class tries to implement an interface and does not define all the method declared in the interface as specified
  2. When multiple related classes (e.g. Database, MySQLDatabase, OracleDatabase) implement exactly 1 interface, it ensures that all classes implementing that interface will always contain all the methods declared in the interface and ensures that the common methods specified in the interface will always accept the same number of arguments for all classes. This makes it very easy to switch between related classes (e.g. migrating from a MySQLDatabase to an OracleDatabase) without editing the external code provided that they both implement the same interface
  3. A class can implement multiple interfaces which is a clear advantage against classical inheritance in PHP (where a child class can only inherit from exactly one parent) as the implementation of multiple interfaces allows for flexibility and the creation of semi-related classes which may each share certain common methods but differ in other respects. Multiple interface implementation also has the added advantage that it exhibits none of the weaknesses inherent in multiple inheritance in classes (in other languages of course not PHP as PHP does not allow multiple class inheritance) such as the diamond problem as explained in Wikipedia.

Further Reading

For more information on PHP interfaces and why you may want to use them (especially for large PHP projects that require multiple developers to collaborate with each other), you may want to read the articles below:

  1. php.net manual on Object Interfaces
  2. Stack Overflow - Why use PHP interfaces?
  3. Why you should always use PHP interfaces by Dave Gardner
  4. Abstract Classes and Interfaces in PHP
interface MyInterface {
  // Interface Constant - cannot be overriden by class implementing it
  const INTERFACE_CONSTANT = "Interface Constant";
  // Public Method Declaration - the method declared below must be defined in the classes implementing the interface
  public function compulsory_method_1();
  public function compulsory_method_2($a);
  public function compulsory_method_3($a, $b);
  public function compulsory_method_4(...$arguments);
  public function compulsory_method_5($argument = "default value");
}

// Class implementing the interface defined above
// Note that instead of using the `extends` keyword, the `implements` keyword is used when a class implements an interface
class MyClass implements MyInterface {
  // Class Constant - has nothing to do whatsoever with the interface the class is implementing
  const CLASS_CONSTANT = "Class Constant";
  // Public, private and protected properties - the interface does not care how many of such properties exists in the class implementing it (or whether such properties even exist in the class) as long as the public methods declared in the interface is defined in the class implementing it
  public $public_property = "public property";
  protected $protected_property = "protected property";
  private $private_property = "private property";
  // Public methods declared in the interface must be defined in the class implementing it
  public function compulsory_method_1() {
    // The interface doesn't care what code is in the method being defined as long as it is public and defined with the exact number of parameters that the interface specifies
    echo "Hello World<br />";
  }
  public function compulsory_method_2($argument) {
    // The name of the method parameter(s) inside the class does not matter as long as the method in the class accepts exactly as many parameters as the method in the interface specifies
    echo "$argument<br />";
  }
  public function compulsory_method_3($a, $b) {
    echo "$a<br />$b<br />";
  }
  public function compulsory_method_4(...$args) {
    echo $this->protected_method(...$args) . "<br />";
  }
  public function compulsory_method_5($param = "Hello World") {
    // Even the default values of parameters in the class method do not have to match those specified in the interface as long as a default value is there
    echo "$param<br />";
  }
  // Other Class Methods - a class implementing an interface is free to have other methods (public, protected or private) not specified in the interface
  protected function protected_method(...$args) {
    return implode("<br />", $args);
  }
}

// An interface constant can be directly accessed without a class implementing it
echo MyInterface::INTERFACE_CONSTANT . "<br />";

// Classes implementing said interface also retain the interface Constant
echo MyClass::INTERFACE_CONSTANT . "<br />";

// Class's own constant
echo MyClass::CLASS_CONSTANT . "<br />";

// Class Methods

$object = new MyClass;
$object->compulsory_method_1();
$object->compulsory_method_2("I love PHP");
$object->compulsory_method_3("PHP is cool", "PHP is fun");
$object->compulsory_method_4("PHP is interesting", "PHP is fascinating", "PHP is amazing", "PHP is astonishing", "PHP for the win!");
$object->compulsory_method_5(); // Using the class's default value, NOT the interface's default