commit
ae3973a5d0
@ -0,0 +1,23 @@ |
||||
<?php |
||||
/** |
||||
* @todo sudo apt install php8.4-bcmath |
||||
* @todo sudo apt install php8.4-intl |
||||
*/ |
||||
|
||||
use BcMath\Number; |
||||
|
||||
require "libs/Dollars.php"; |
||||
|
||||
function init(): Number { |
||||
$num1 = new Number('2200'); |
||||
$num2 = new Number('700'); |
||||
$money = ($num1 / $num2) + $num1 - $num2; |
||||
//echo bcround($result, 2); |
||||
return $money; |
||||
} |
||||
|
||||
$d = new Dollars(); |
||||
$c = init(); |
||||
echo $d->formatAsUSD($c); |
||||
echo "\n"; |
||||
echo $d->intlUSD($c); |
||||
@ -0,0 +1,26 @@ |
||||
<?php |
||||
interface HasAuthors { |
||||
public string $credits { get; } |
||||
public Author $mainAuthor { get; set; } |
||||
} |
||||
|
||||
class Author { |
||||
public function __construct(public private(set) string $name) {} |
||||
} |
||||
|
||||
class Book implements HasAuthors { |
||||
public string $credits { |
||||
get => "Authors: David Smith\n"; |
||||
} |
||||
|
||||
public Author $mainAuthor { |
||||
get => new Author("Smith"); |
||||
set => throw new Exception("Main author cannot be changed."); |
||||
} |
||||
} |
||||
|
||||
$book = new Book(); |
||||
echo $book->credits; |
||||
|
||||
$author = $book->mainAuthor; |
||||
echo $author->name; |
||||
@ -0,0 +1,36 @@ |
||||
<?php |
||||
interface SizeInterface { |
||||
public function getSize(): string; |
||||
} |
||||
|
||||
enum Size: string implements SizeInterface { |
||||
case Small = 'small'; |
||||
case Grande = 'grande'; |
||||
|
||||
public function getSize(): string { |
||||
return $this->value; |
||||
} |
||||
} |
||||
|
||||
|
||||
class Coffee { |
||||
public string $flavor { |
||||
get { |
||||
return $this->flavor . ' Spice'; |
||||
} |
||||
set(string $value) { |
||||
if (strlen($value) > 16) throw new InvalidArgumentException('Input is too long'); |
||||
$this->flavor = $value; |
||||
} |
||||
} |
||||
|
||||
public function serve(SizeInterface $size): void { |
||||
echo "\r\nServing a {$size->getSize()} coffee.\n"; |
||||
} |
||||
} |
||||
|
||||
$coffee = new Coffee(); |
||||
$coffee->flavor = 'Pumpkin'; |
||||
echo $coffee->flavor; |
||||
|
||||
$coffee->serve(Size::Grande); |
||||
@ -0,0 +1,9 @@ |
||||
<?php |
||||
class Dog { |
||||
public function bark(): string { |
||||
return "Woof!"; |
||||
} |
||||
} |
||||
|
||||
$dog = new Dog()->bark(); |
||||
echo $dog; |
||||
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
require "libs/LazyCollection.php"; |
||||
|
||||
$lazyCollection = LazyCollection::make(function () { |
||||
try { |
||||
$handle = fopen('huge.txt', 'r'); |
||||
if (!$handle) throw new Exception("Could not open file"); |
||||
|
||||
while (($line = fgets($handle)) !== false) { |
||||
yield $line; |
||||
} |
||||
} finally { |
||||
if (isset($handle) && is_resource($handle)) { |
||||
fclose($handle); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
ob_start(); |
||||
$lazyCollection->each(function ($line) { |
||||
echo $line; |
||||
ob_flush(); |
||||
flush(); |
||||
}); |
||||
ob_end_flush(); |
||||
@ -0,0 +1,20 @@ |
||||
<?php |
||||
class Example { |
||||
public function __construct(public int $data) { |
||||
echo __METHOD__, "\n"; |
||||
} |
||||
} |
||||
|
||||
$initializer = static function (Example $ghost): void { |
||||
// Initialize |
||||
$ghost->__construct(1); |
||||
}; |
||||
|
||||
$reflector = new ReflectionClass(Example::class); |
||||
$object = $reflector->newLazyGhost($initializer); |
||||
|
||||
var_dump($object); |
||||
var_dump($object instanceof Example); |
||||
|
||||
// Triggers initialization, and fetches the property after that |
||||
var_dump($object->data); |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
require "libs/LazyObject.php"; |
||||
|
||||
class MyClass { |
||||
public function __construct(public int $num) {} |
||||
public function someMethod() { |
||||
return $this->num; |
||||
} |
||||
} |
||||
|
||||
class Example2 { |
||||
public function hi() { echo "Hi!"; } |
||||
} |
||||
|
||||
$object = new LazyObject()->proxy(MyClass::class, 301); |
||||
// The object is initialized only when accessed |
||||
echo $object->someMethod() . "\n"; |
||||
|
||||
$objectB = new LazyObject()->proxy(Example2::class); |
||||
$objectB->hi(); |
||||
@ -0,0 +1,3 @@ |
||||
<?php |
||||
$name ??= "Bobby"; |
||||
echo $name; |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
use BcMath\Number; |
||||
|
||||
class Dollars { |
||||
private function moneyAsFloat(Number $money): float { |
||||
// Remove any existing currency symbols and thousands separators |
||||
$t = preg_replace('/[^\d.-]/', '', $money); |
||||
return (float)$t; |
||||
} |
||||
|
||||
public function formatAsUSD(Number $money): string { |
||||
return '$' . number_format($this->moneyAsFloat($money), 2, '.', ','); |
||||
} |
||||
|
||||
public function intlUSD(Number $money): string { |
||||
if (class_exists('NumberFormatter')) { |
||||
$formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY); |
||||
return $formatter->formatCurrency($this->moneyAsFloat($money), 'USD'); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,63 @@ |
||||
<?php |
||||
class LazyCollection implements IteratorAggregate |
||||
{ |
||||
protected $source; |
||||
|
||||
public function __construct($source = null) |
||||
{ |
||||
if ($source instanceof Closure || $source instanceof self) { |
||||
$this->source = $source; |
||||
} elseif (is_null($source)) { |
||||
$this->source = static::empty(); |
||||
} else { |
||||
$this->source = $this->getArrayableItems($source); |
||||
} |
||||
} |
||||
|
||||
public function getIterator(): Traversable |
||||
{ |
||||
return $this->makeIterator($this->source); |
||||
} |
||||
|
||||
protected function makeIterator($source) |
||||
{ |
||||
if ($source instanceof Closure) { |
||||
$source = $source(); |
||||
} |
||||
|
||||
if (is_array($source)) { |
||||
return new ArrayIterator($source); |
||||
} |
||||
|
||||
return $source; |
||||
} |
||||
|
||||
public static function make($source = null) |
||||
{ |
||||
return new static($source instanceof Closure ? $source() : $source); |
||||
} |
||||
|
||||
public function each(callable $callback) |
||||
{ |
||||
foreach ($this->getIterator() as $key => $value) { |
||||
if ($callback($value, $key) === false) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
protected function getArrayableItems($items) |
||||
{ |
||||
if (is_array($items)) { |
||||
return $items; |
||||
} elseif ($items instanceof Traversable) { |
||||
return iterator_to_array($items); |
||||
} elseif (is_object($items) && method_exists($items, 'toArray')) { |
||||
return $items->toArray(); |
||||
} |
||||
|
||||
return (array) $items; |
||||
} |
||||
} |
||||
@ -0,0 +1,26 @@ |
||||
<?php |
||||
class LazyObject { |
||||
public function proxy(string $className, mixed $c = null) { |
||||
if (!class_exists($className, true)) { |
||||
throw new InvalidArgumentException("Class {$className} does not exist"); |
||||
} |
||||
$reflector = new ReflectionClass($className); |
||||
if (!$reflector->isInstantiable()) { |
||||
throw new InvalidArgumentException("Class {$className} cannot be instantiated"); |
||||
} |
||||
$constructor = $reflector->getConstructor(); |
||||
|
||||
// If the class has a constructor with required parameters |
||||
if ($constructor && $constructor->getNumberOfRequiredParameters() > 0) { |
||||
$initializer = static function (mixed $i) use ($className) { |
||||
return new $className($i); |
||||
}; |
||||
return $reflector->newLazyProxy(fn() => $initializer($c)); |
||||
} else { |
||||
$initializer = static function () use ($className) { |
||||
return new $className(); |
||||
}; |
||||
return $reflector->newLazyProxy($initializer); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue