There might be couple nuances to be considered carefully:
-
For
SELECT *I recommend narrowing the selection to only the specific columns required for the task. This reduces the size of each row object and further optimizes the migration's performance -
Using fetchAll() is memory-intensive as it attempts to load the entire result set into an array. I would refactor this to iterate through the rows one-by-one to keep the memory footprint low, like this:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// manipulate the data here
}
- Furthermore, we should reconsider the necessity of processing the entire table in a single execution. For massive datasets, I would implement chunking (using LIMIT and OFFSET or, preferably, a primary key range) to process the data in manageable batches.
This is a classic "falsy" value bug. If "superman" is at the start of the string, indexOf() returns 0. In JavaScript, !0 evaluates to true, causing the error to throw even though the word was found.
if (str.toLowerCase().indexOf('superman') === -1) {//You must explicitly check against -1.
throw new Error('String does not contain superman');
}
I chose a PHP implementation that focuses on data normalization (stripping non-digits) before applying the format.
function phoneNumberSplitter(string|int $number, string $delimiter = '-') : string {
$nums = preg_replace('/\D/', '', (string) $number);
if (strlen($nums) !== 10) {
throw new InvalidArgumentException('Invalid US phone number');
}
return implode($delimiter, [
substr($nums, 0, 3),
substr($nums, 3, 3),
substr($nums, 6),
]);
}In JavaScript, this is often handled more elegantly with a single .replace() and a regex using capture groups (e.g., (\d{3})(\d{3})(\d{4})).
To ensure consistency (determinism), we must hash the string. I used a simple bitwise hash to generate a numeric value from the name, then converted that number into a hex string.
function getColorFromName(string $name): string
{
$hash = 0;
$length = strlen($name);
for ($i = 0; $i < $length; $i++) {
$charCode = ord($name[$i]);
$hash = ($hash * 31 + $charCode) & 0xFFFFFFFF; // 32-bit integer
}
$red = ($hash >> 16) & 0xFF;
$green = ($hash >> 8) & 0xFF;
$blue = $hash & 0xFF;
$redHex = str_pad(dechex($red), 2, '0', STR_PAD_LEFT);
$greenHex = str_pad(dechex($green), 2, '0', STR_PAD_LEFT);
$blueHex = str_pad(dechex($blue), 2, '0', STR_PAD_LEFT);
return '#' . $redHex . $greenHex . $blueHex;
}Testing should cover the "Happy Path," boundary values, and expected exceptions. In PHP:
final class FizzBuzzTest extends TestCase
{
public function testDefaultRange(): void
{
$result = fizzBuzz();
$this->assertStringContainsString('Fizz', $result);
$this->assertStringContainsString('Buzz', $result);
$this->assertStringContainsString('FizzBuzz', $result);
}
public function testSingleNumberFizz(): void
{
$this->assertSame('Fizz', fizzBuzz(3, 3));
}
public function testSingleNumberBuzz(): void
{
$this->assertSame('Buzz', fizzBuzz(5, 5));
}
public function testSingleNumberFizzBuzz(): void
{
$this->assertSame('FizzBuzz', fizzBuzz(15, 15));
}
public function testSingleNumberNormal(): void
{
$this->assertSame('7', fizzBuzz(7, 7));
}
public function testSmallRange(): void
{
$this->assertSame(
'12Fizz4BuzzFizz78FizzBuzz',
fizzBuzz(1, 15)
);
}
public function testCustomRange(): void
{
$this->assertSame(
'FizzBuzz1617Fizz19Buzz',
fizzBuzz(15, 20)
);
}
public function testStartEqualsStop(): void
{
$this->assertSame('Fizz', fizzBuzz(6, 6));
}
public function testZeroIsAllowed(): void
{
// 0 is divisible by 3 and 5
$this->assertSame('FizzBuzz', fizzBuzz(0, 0));
}
public function testStopLessThanStartThrowsException(): void
{
$this->expectException(InvalidArgumentException::class);
fizzBuzz(10, 5);
}
public function testNegativeStartThrowsException(): void
{
$this->expectException(InvalidArgumentException::class);
fizzBuzz(-1, 10);
}
public function testNegativeStopThrowsException(): void
{
$this->expectException(InvalidArgumentException::class);
fizzBuzz(1, -10);
}
}In JS:
describe('fizzBuzz', () => {
test('default range contains Fizz, Buzz, FizzBuzz', () => {
const result = fizzBuzz();
expect(result).toContain('Fizz');
expect(result).toContain('Buzz');
expect(result).toContain('FizzBuzz');
});
test('single Fizz', () => {
expect(fizzBuzz(3, 3)).toBe('Fizz');
});
test('single Buzz', () => {
expect(fizzBuzz(5, 5)).toBe('Buzz');
});
test('single FizzBuzz', () => {
expect(fizzBuzz(15, 15)).toBe('FizzBuzz');
});
test('custom range', () => {
expect(fizzBuzz(1, 15))
.toBe('12Fizz4BuzzFizz78FizzBuzz');
});
test('throws if stop < start', () => {
expect(() => fizzBuzz(10, 5)).toThrow();
});
test('throws on negative start', () => {
expect(() => fizzBuzz(-1, 10)).toThrow();
});
test('throws on negative stop', () => {
expect(() => fizzBuzz(1, -10)).toThrow();
});
});In JavaScript (using Jest or Mocha), the testing logic is similar, but the syntax for catching errors differs (using a wrapper function inside expect().toThrow())
The bug is caused by var being function-scoped, not block-scoped.
The fix is next:
for (let i = 0; i < 10; i++) {
button.onclick = () => console.log(i);
}In JavaScript, an object is iterable if it implements the @@iterator method, accessed via Symbol.iterator.
function isIterable(value) {
return value != null && typeof value[Symbol.iterator] === 'function';
}<?php
class Document
{
private User $user; //changed to private
private string $name; //changed to private
/**
* 1. Replaced the old init() method.
* 2. I would like to see validation somewhere else
*/
public function __construct(string $name, User $user)
{
if (strlen($name) <= 5) {
throw new InvalidArgumentException('Document name must be longer than 5 characters');
}
$this->name = $name;
$this->user = $user;
}
public function getTitle(): string
{
//definitely can be DI instead the direct call
$db = Database::getInstance();
// prepared statements wold be nice hereto prevent SQL injection
$row = $db->query(
'SELECT title FROM document WHERE name = "' . $this->name . '" LIMIT 1'
);
// looks weird to me, ask third column? better use named column
return $row[3];
}
/**
* Single responsibility principle violation, Document knows how to query data
* (by the way same is applicable to getTitle())
* they both should be implemented within a DocumentRepository
*/
public static function getAllDocuments(): array
{
// to be implemented later
}
}
class User
{
public function makeNewDocument(string $name): Document
{
// strpos() can return 0, which previously caused a false negative
if (strpos(strtolower($name), 'senior') === false) {
throw new InvalidArgumentException('The name should contain "senior"');
}
return new Document($name, $this);
//no need for $doc->init($name, $this) anymore
}
/**
* 1.Filtering an be done at the data source level,not in memory.
* 2. I don't get idea having all document regardles the user, it's worth extract user first to see all his documents
*
*/
public function getMyDocuments() {
$list = array();
foreach (Document::getAllDocuments() as $doc) {
if ($doc->user == $this)
$list[] = $doc;
}
return $list;
}
}