The CRUD interface I created for my new app. Creates, updates, deletes, reads and lists Here is the Interface I am using in my working app. 


&lt;?php

declare(strict_types=1);

namespace midorikocak\nano;

use Exception;

interface CrudInterface
{

    /**
     * @param array $data Array data of an Item.
     * @return array Array data of an Item with id.
     * @throws Exception if the data does not pass validate
     */
    public function create(array $data): array;

    /**
     * @param string $id
     * @return array Returns the array of New Item.
     * @throws Exception if something bad happens
     */
    public function read($id): array;

    /**
     * @param string $id Can be an integer or a string
     * @param array $data Accepts Array data of an Item with or without id.
     * @return array Returns the array of Updated Item.
     * @throws Exception if something bad happens
     * @todo Is it ok to have id in array data?
     */
    public function update(string $id, array $data): array;

    /**
     * @param string $id Can be an integer or a string
     * @return void Returns nothing. Simple Command Query separation.
     * @throws Exception if id not found or something bad happens
     * @todo Should create different exceptions for negative outcomes
     */
    public function delete(string $id): void;

    /**
     * @return array[] Should return an array of arrays that contain Item Data.
     */
    public function list(): array;

    /**
     * We have to validate data in every operation that receives item array.
     * @param array $data Accepts Array data of an Item with or without id.
     * @todo How can we be sure that this runs in every method that acceps item data?
     * @todo Maybe an abstract class?
     *
     * @return bool
     */
    public function validateData(array $data): bool;
}


I have some questions.


In update method, is it ok to have id in array data?
Should I create different exceptions for negative outcomes? Instead of returning false or null, when something is wrong, I prefer to throw exceptions.
How can we be sure that In validateData method runs in every method that accepts item data? Maybe an abstract class?
Are there any violations or can it be some better?
Ad 1) it Is ok to pass id in the Array data of you want to change the id. If you were asking if you can omit the id argument. Then yes but you Will never be able to change id And honestly it becomes more verbose to use. And honestly it Is quite premature to expect this on this generic level.

Ad 2) if "wrong" means empty id or database unreachable and similar, then yes, throw (or pass up) exceptions. But if it means object with given id not found then return null, it is not exceptional to ask for non-existent id, it just leads to a different result. But when database is unreachable, you are unable to say wheteher it exists or not and if it does what are its data and so here exception is appropriate.

Although many will argue here that exceptions are better. I think that exceptions are there to halt program (and do cleanup and notify someone) when something went really bad, not to be used to control flow of your program.

Ad 3) You have (at least) 2 options here:

Dont make it part of the interface. Let implementations take care of this. Could be abstrakt but in generál i advise against abstract classes as they sooner or later start cousing troubles when an implementation wants something done slightly differently And nobody thought about it when the abstract class was designed.

Or,

if it is / has to be part of the interface than it might better return error messages/codes instead of just bool. And the caller should be responsible for calling it first, if He does not call IT than the interface Is being used incorrectly And anything can happen, but that would be a dev's Mistake.

To provide an analogy, it would be like calling Iterator::current() before making sure Iterator::valid() returned true -> undefined behaviour, anything can happen, exception thrown, or nothing, or random element returned, or anything else - simply whatever was the most convenient for that implementation, anyway it is not important because at that point the interface is being misused and the code calling it is wrong and need to be fixed.

Calling it from inside the other method (valid from current, or validateData from create/update) just to make sure that the first method returns true and throw exception otherwise is also wrong because it will get called twice (redundantly) for whoever used the interface correctly. 

Although many (especialy PHP) devs may argue that it is better to always throw exception to make sure the dev notices this as soon as possible. I personaly think that you should just write it into the interface's doc comments to state very explicitly that calling create/update without validating the data first is undefined behaviour. How many consumer classes will there be for CrudInterface anyway? One? Two? You make sure that these are correct and then everyone is going to use them, right? So...