Learn from your fellow PHP developers with our PHP blogs, or help share the knowledge you've gained by writing your own.
class IntArray {
private $values = [];
public function add(int $value) {
$this->values[] = $value;
}
}
Then, whenever you need an array of integers, you may write something like this:class BatchProcessor
{
private $ids;
public function __construct(IntArray $ids) {
$this->ids = $ids;
}
}
Not bad. You'll need a class per type, though, and that may seem a bit of an overkill for such a simple task. Luckily, same result can be achieved differently, but with the same level of confidence in every value type:class BatchProcessor
{
private $ids;
public function __construct(int ...$ids) {
$this->ids = $ids; }
}
Voila - no need for extra class! This approach uses the PHP 7's type hinting for scalar types, in conjunction with Variable length argument lists available since PHP 5.6. In fact, variable-length argument lists have been around since probably the very first version of the language, but in 5.6 they were revisited and got some nice syntactic sugar in form of "...", so you declare and call them as easy as this:function func(...$args){...}
$args = [1, 2, 3];
func(...$args);
The approach can work with any type-hinting available in PHP, and I hope you find it somewhat useful! Comment, discuss share and ask questions - I'll be around.n
items are put into m
containers, with n > m
, then at least one container must contain more than one item. Mathematicians can be even more weird then programmers, can't they? And remember, programmers can right something like if (true == false)...
Me: Is that really important that the tables are MyISAM? It's 2018, you know.. There are dozens of queries in queue waiting for table-level locks.
R**: Are they MyISAM? Really?
Me: Yes.. Any objection against converting them to InnoDB? With the current state of the website, with all those tons of Gateway Timeouts, it's not going to make it worse if I do it right now..
Me: Nah, it didn't help a lot.. But, looking at the SHOW PROCESSLIST output, I see something weird. What, do you think, this query does? SELECT LAST_INSERT_ID() FROM images?
R**: ehh... Gets you the last AUTO_INCREMENT id from images table?
Me: Let's play another good news bad news joke.. Good news: you're right, it gets you the last AUTO_INCREMENT id. Bad news: it's not for table, it's for the session. Worse news: this query gets you the last AUTO_INCREMENT id and does it exactly as many times as there are rows in the images table. how many are there?
R**: about 8mln. #@%&! It's sending 8mln rows on every image upload, through the network!
Me: Bingo! 8mln rows, with one and the same integer value in all of them.
R**: Ouch... Aaaand... Before today, it was not an issue. Because the database was on the same server as the application..
Me: Exactly, it used the loopback interface, and now it's using ehternet, which, apparently, doesn't have a super good bandwidth. We don't have a gigabit channel between servers, do we?
R**: No, it's 100 Mbit
Me: Are you fixing the query, BTW?
R**: yeah, man, deploying it...
As we express our gratitude, we must never forget that the highest appreciation is not to utter words, but to live by them. - John F. Kennedy
$users = [new User(), new User()];
I see a lost opportunity to use Iterator.public function getUsers(): array
{
return $userArray;
}
public function setUsersToActiveState()
{
$users = $this->getUsers();
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
There immediately two problems occurred.
class UsersCollection implements \IteratorAggregate
{
private $users = [];
public function getIterator() : UserIterator
{
return new UserIterator($this);
}
public function getUser($position)
{
if (isset($this->users[$position])) {
return $this->users[$position];
}
return null;
}
public function count() : int
{
return count($this->users);
}
public function addUser(User $users)
{
$this->users[] = $users;
}
}
class UserIterator implements \Iterator
{
private $position = 0;
private $userCollection;
public function __construct(UsersCollection $userCollection)
{
$this->userCollection = $userCollection;
}
public function current() : User
{
return $this->userCollection->getUser($this->position);
}
public function next()
{
$this->position++;
}
public function key() : int
{
return $this->position;
}
public function valid() : bool
{
return !is_null($this->userCollection->getUser($this->position));
}
public function rewind()
{
$this->position = 0;
}
}
class UsersCollectionTest extends TestCase
{
public function testUsersCollectionShouldReturnNullForNotExistingUserPosition()
{
$usersCollection = new UsersCollection();
$this->assertEquals(null, $usersCollection->getUser(1));
}
public function testEmptyUsersCollection()
{
$usersCollection = new UsersCollection();
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals(0, $usersCollection->count());
}
public function testUsersCollectionWithUserElements()
{
$usersCollection = new UsersCollection();
$usersCollection->addUser($this->getUserMock());
$usersCollection->addUser($this->getUserMock());
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals($this->getUserMock(), $usersCollection->getUser(1));
$this->assertEquals(2, $usersCollection->count());
}
private function getUserMock()
{
}
}
class UserIteratorTest extends MockClass
{
public function testCurrent()
{
$iterator = $this->getIterator();
$current = $iterator->current();
$this->assertEquals($this->getUserMock(), $current);
}
public function testNext()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(1, $iterator->key());
}
public function testKey()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$this->assertEquals(2, $iterator->key());
}
public function testValidIfItemInvalid()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$iterator->next();
$this->assertEquals(false, $iterator->valid());
}
public function testValidIfItemIsValid()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(true, $iterator->valid());
}
public function testRewind()
{
$iterator = $this->getIterator();
$iterator->rewind();
$this->assertEquals(0, $iterator->key());
}
private function getIterator() : UserIterator
{
return new UserIterator($this->getCollection());
}
private function getCollection() : UsersCollection
{
$userItems[] = $this->getUserMock();
$userItems[] = $this->getUserMock();
$usersCollection = new UsersCollection();
foreach ($userItems as $user) {
$usersCollection->addUser($user);
}
return $usersCollection;
}
private function getUserMock()
{
}
}
public function getUsers(): UsersCollection
{
$userCollection = new UsersCollection();
foreach ($whatIGetFromDatabase as $user) {
$userCollection->addUser($user);
}
return $userCollection;
}
public fucntion setUsersToActiveState()
{
$users = $this->getUsers();
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
As you can see setUsersToActiveState remains the same, we only do not need to specify for our IDE or collagues what type $users variable is. public function addUser(User $users)
{
if ($user->getAge() > 18) {
$this->users[] = $users;
}
}
public function addUsers(array $users)
{
foreach($users as $user) {
$this->addUser(User $users);
}
}