Types of tests

Unit Testing

Unit Testing: Analysing a small piece of code is known as Unit Testing. Each unit test targets a unit of code in isolation. Unit testing should be as simple as possible, and it should not be depended on another functions/classes.

Тестваме само отделните методи на даденият клас. При подаване на някакви тестови аргументи, и знаейки какъв резултат трябва да буде върнат, виждаме дали методът работи правилно.

Не се допуска взаимодействие с какъвто и да било storage (DB, files…) както и например HTTP заявки към други компютри. Ако например ни трябва работа с DB, то фейкваме самата връзка за та не се осъществи реално работа с DB.

Всеки тест е напълно независим от останалите.

Functional Testing

Тези тестове имат цел про да симулират потребителското взаимодействие с SUT като например посредством браузър.
„Отвори този URL, събмитни дадена форма, в отговора има ли даден текст…“

Integration Testing

Много близък до Unit test тип, с разликата че работим реално с DB или друг сторидж.

Acceptance Testing

Acceptance Testing: This is the last phase of the testing process. Here we check the behavior of whole application from users side. End users insert the data and check the output whether it meets the required specifications or not. They just check the flow, not the functionality.

Допускат се взаимодействие с storage (DB, files…) както и например HTTP заявки към други компютри. Тестваме цялостното поведение на SUT от позицията на външен поребител.

Литература:

https://www.valuebound.com/resources/blog/understanding-phpunit-and-how-to-write-unit-test-cases

Convention over configuration

Принцип в софтуерният дизайн, при който се стремим колкото се може повече неща, които иначе се задават чрез напримен конфиг файлове и прочее конфигурации… да се подразбират сами.

Например, имаме модел Users, зад който имаме таблица в базата, наречена users. Ето един пример за Convention over configuration – вместо да имаме конфиг-настройка, приемаме че щом моделът се казва така, и таблицата защо да не се казва така.

Явно идеята на този принцип е да се използват еднакви имена, за да се намали факторът конфигуриране.

Оpaque (нищо не значещ) string

Понятие, означаващо символен низ, чието значение няма нужда да знаем, а по-скоро го използваме с условни цели. Например – като ID, като някакъв идентификатор…

Явно затова му казват „opaque“, демек непрозрачен, тоест служебен, протоколен, не ни интересува конкретното му значение. Просто го използваме за други цели без да ни интересува той самият какво значи.

Или както се казва: „do not assume that the structure of the string carries any semantic meaning“.

Separation of concerns (SoC)

Според мен това е design принцип, много подобен на Inversion of Control, но в по-общ смисъл. Демек, IoC е по-конкретен само за OOP, SoC e по-общ…

Принцип при който чрез разделяне на функционалността на дадена програма по такъв начин, че отделните и компоненти (класове, пакети, библиотеки…) да са както максимално концентрирани само върху своите задачи и предназначения (single responsibility) и да имат максимално тясна специализация.

„In computer scienceseparation of concerns (SoC) is a design principle for separating a computer program into distinct sections such that each section addresses a separate concern.“

Въпросното „разделяне на задачи“ може да е на различен принцип. Това може да са задачи свързани само с визуалната част на дадената програма, както например HTML и CSS си разделят отговорностите, едното за структурата и семантиката, а другото – за чисто визуалната част на дадената страница. Затова в началото казахме, че „SoC e по-общ“.

Може да е чисто backend разделяне на програмата – един клас да отговаря за валидациите, друг за работа с базата данни…

Или още по-генерално как да се структурира програмата. MVC например е типичен пример за SoC – програмата е разделена на бизнес модел, презентационна част и т.н…

OOP encapsulation, granularity, dependency, flexibility, performance, evolution and reusability and other common concepts

Цитатите са от известната книга „Design Patterns: Elements of Reusable Object-Oriented Software“

Object types and interfaces

A type is a name used to denote a particular interface. We speak of an object as having the type „Window“ if it accepts all requests for the operations defined in the interface named „Window.“ An object may have many types, and widely different objects can share a type. Part of an object’s interface may be characterized by one type, and other parts by other types. Two objects of the same type need only share parts of their interfaces. Interfaces can contain other interfaces as subsets. We say that a type is a subtype of another if its interface contains the interface of its supertype. Often we speak of a subtype inheriting the interface of its supertype.

Interfaces are fundamental in object-oriented systems. Objects are known only through their interfaces. There is no way to know anything about an object or to ask it to do anything without going through its interface. An object’s interface says nothing about its implementation – different objects are free to implement requests differently. That means two objects having completely different implementations can have identical interfaces.

Видиш ли интерфейсът на даден клас, виждаш какво той може да прави, видиш ли самият клас (имплементация), виждаш как го прави.

Dynamic binding

When a request is sent to an object (calling some of its methods), the particular operation that’s performed, depends on both the request and the receiving object. Different objects that support identical requests may have different implementations of the operations that fulfill these requests (или казано иначе, имплементират по различен начин различни интерфейси). The run-time association of a request to an object and one of its operations is known as dynamic binding.

Dynamic binding means that issuing a request (calling а object method) doesn’t commit you to a particular implementation until run-time. Consequently, you can write programs that expect an object with a particular interface, knowing that any object that has the correct interface will accept the request.

Polymorphism

Dynamic binding lets you substitute objects that have identical interfaces for other, at run-time. This substitutability is known as polymorphism, and it’s a key concept in object-oriented systems.

Kакво е т.н. „интерфейс“?
Какво даден клас може да прави чрез методите си?
Да де, но не само. Интерфейс MagareInterface задължава имплементиращите го класове да могат да ревът и да хвърлят къчове.
Но идеята е интерфейс MagareInterface да задължи дадените методи на имплементиращи даденият интерфейс, да имат зададеният от интерфейсът сигнъчър, демек, да се знае какво се иска като типове параметри, както и като тип върнат резултат.

Classes that aren’t abstract are called concrete classes.

Object’s class vs. Object’s type

It’s important to understand the difference between an object’s class and its type. An object’s class defines how the object is implemented. The class defines the object’s internal state and the implementation of its operations. In contrast, an object’s type only refers to its interface – the set of requests to which it can respond. An object can have many types, and objects of different classes can have the same type.

Демек, класът на даден обект представлява самата му дефиниция. Това е все едно конституцията и законите на една държава, според които тя функционира.

Типът на даденият обект задава неговият интерфейс, тоест как той (обектът) комуникира с останалият свят, тоест какви заявки може да приема и обслужва. Типът е така да се каже „външната политика“ на гореспоменатата държава.

„… and objects of different classes can have the same type.“ – много държави могат да имат обща външна политика най-общо казано, като например членство в едни и същи организации и т.н…

Разбира се, двете понятия за близко свързани помежду си.
Of course, there’s a close relationship between class and type. Because a class defines the operations an object can perform, it also defines the object’s type. When we say that an object is an instance of a class, we imply that the object supports the interface defined by the class.
Демек, понеже класът задава конституцията, то индиректно той задава и външната политика. И щом кажем, че обектът е от клас ЕдикойСи (демек има конституция ЕдикойСи), това по подразбиране значи, че той има и съответната външна политика.

Като пишеш един клас, винаги мислиш първо „какво трябва да може да прави“, и тогава, на тази база пишеш конкретната имплементация. Демек, класът задава конституцията но според това какъв трябва да е типът – външната политика. Явно това се има предвид с принципът „Program to an interface, not an implementation.“

Inheritance vs. Composition

The two most common techniques for reusing functionality in object-oriented systems are class inheritance and object composition. Subclassing is often referred to as white-box reuse. The term „white-box“ refers to visibility.
Демек, класът който наследяваш е напълно известен за теб, като негов наследник, затова явно се има предвид, че е „бяла кутия“. Наследяваш всичко, без разбира се private’s.

Object composition is an alternative to class inheritance. Here, new functionality is obtained by assembling or composing objects to get more complex functionality. This style of reuse is called black-box reuse, because no internal details of objects are visible. Objects appear only as „black boxes.“
За разлика наследяването, тук другите обекти биват „инджектнати“ като пропъртита. Които обекти могат и да не са ни известни като структура и т.н., дадени са ни да им използваме public пропъртитата и методите, демек знаем за тях само толкова, колкото трябва да знаем. Те за нас са като „черна кутия“.

Inheritance and composition each have their advantages and disadvantages. Class inheritance is defined statically at compile-time and is straightforward to use, since it’s supported directly by the programming language. Class inheritance also makes it easier to modify the implementation being reused.
Демек, така може по-лесно да се променя функционалността на наследяваният клас. Как? Чрез overriding.

But class inheritance has some disadvantages too. First, you can’t change the implementations inherited from parent classes at run-time, because inheritance is defined at compile-time. But you can in compile time.
Second, and generally worse, parent classes often define at least part of their subclasses physical representation. Because inheritance exposes a subclass to details of its parent’s implementation, it’s often said that „inheritance breaks encapsulation“. The implementation of a subclass becomes so bound up with the implementation of its parent class that any change in the parent’s implementation will force the subclass to change.

Демек, ако прекаляваме с наследяването, може да достигнем до огромна и тежка „пирамида“ от класове, губейки капсулираност и гъвкавост.
Your classes and class hierarchies will remain small and will be less likely to grow into unmanageable monsters.

Object composition is defined dynamically at run-time through objects acquiring references to other objects. Composition requires objects to respect each others’ interfaces, which in turn requires carefully designed interfaces that don’t stop you from using one object with many others. But there is a payoff. Because objects are accessed solely through their interfaces, we don’t break encapsulation. Any object can be replaced at run-time by another as long as it has the same type. Moreover, because an object’s implementation will be written in terms of object interfaces, there are substantially fewer implementation dependencies.

Демек, трудността тук е да използваме инджектнатите обекти правилно, според интерфейсите им, тоест и самите интерфейси трябва да са добре направени. Предимството на composition е, че не се нарушава капсулацията, всеки обект е само за себе си, и най-вече – взаимозаменяемостта им на база че са от общ тип (имат общ интерфейс). Демек, не „разширяваш“ даден клас чрез наследяване, а подаваш готов обект от даденият клас, на друг обект.

That leads us to our second principle of object-oriented design: Favor object composition over class inheritance.

Delegation

Това е принцип, който използва composition, на практика постига същият ефект като inheritance но го прави не като наследява даден клас и използва неговите методи и пропъртита с this или self, а получава готов обект като параметър и използва неговите такива.

Relating Run-Time and Compile-Time Structures

An object-oriented program is a run-time structure, that often bears little resemblance to its code structure. The code structure is frozen at compile-time; it consists of classes in fixed inheritance relationships. A program’s run-time structure consists of rapidly changing networks of communicating objects. In fact, the two structures are largely independent. Trying to understand one from the other is like trying to understand the dynamism of living ecosystems from the static taxonomy of plants and animals, and vice versa.
Демек, структурата от класове е все едно енциклопедията с растения и животни, но самата програма е вече съвкупност от динамични обекти, които комуникират помежду си, зависят един от друг…, и това е все едно една жива екосистема, една гора например.

A design that doesn’t take change into account risks major redesign in the future.

String interning

Софтуерна техника, при която повтарящи се стрингове, които не се променят и са еднакви, например конфиг стрингове, не се съхраняват независимо един от друг, а се съхранява само един, и на всички места, където се използва, го достъпваме с указател.

Така се получава хеш структура, наречена string intern pool.

Освен че се пести памет, string interning също и ускорява сравняването на стрингове, защото вместо да се сравняват символ по символ, просто се сравняват дали указателите им са еднакви (a pointer equality test).

В PHP string interning e реализирано от OPcache библиотеката като имаме настройки като „opcache.interned_string_buffer„.

opcache.interned_strings_buffer – A pretty neat setting with like 0 documentation. PHP uses a technique called string interning to improve performance— so, for example, if you have the string „foobar“ 1000 times in your code, internally PHP will store 1 immutable variable for this string and just use a pointer to it for the other 999 times you use it. Cool. This setting takes it to the next level— instead of having a pool of these immutable string for each SINGLE php-fpm process, this setting shares it across ALL of your php-fpm processes. It saves memory and improves performance, especially in big applications. The value is set in megabytes, so set it to „16“ for 16MB. The default is low, 4MB.

Fail Fast principle

The fail fast principle stands for stopping the current operation as soon as any unexpected error occurs. Adhering to this principle generally results in a more stable solution. It might appear counter-intuitive at first. How is it so that failing at any error leads to stability? Isn’t it backward?

Литература:

https://enterprisecraftsmanship.com/posts/fail-fast-principle/

Design Principle vs. Design Pattern

Първо, важно е да споменем две понятия и да разбере разликата между тях –
Design Principle и Design Pattern.

Design Principle е така да се каже по-общото. Това са общи, добри практики, които е добре да се спазват, независимо от езика за програмиране и не предлагат конкретни начини на приложение. Това са чисто абстракни принципи.

Един пример за design principles са например SOLID принципите.

Design patterns са вече по-конкретни решения на различни проблеми от ООП, но спазвайки design principles. Например, искаме от даден клас да имаме само един обект – използваме Singleton design pattern, ето това е една design pattern.

Design patterns са отново независими от езикът за програмиране както design principles, но са по-скоро практическото приложение на design principles.

Също, когато прилагаме или създаваме design pattern, трябва винаги да внимаваме да не нарушаваме design principle. По принцип един клас винаги се пише така, че да има една „основна отговорност“, заради която бива писан, и отделно – различни, така да се каже „помощни“ функционалности, като например логери, емайл, спелчекъри…
За такива е идеята – да бъдат отделени като отделни класове и да бъдат инджектвани.

Литература:

https://www.tutorialsteacher.com/articles/difference-between-design-principle-and-design-pattern

Inversion of Control principle (IoC), Dependency Inversion principle (DIP) и Dependency Injection (DI)

Dependency Injection (DI)

Когато можем да инджектваме даден обект в друг обект.

Така се реализира design принципът Inversion of Control, демек – на практика реализиране на Single Responsibility SOLID принципът.

Types of Dependency Injection
  1. Constructor Injection – през конструктора, демек инджектваният обект се подава oще на конструктора на основният клас и се сетва като пропръти още при инстанциране на основният обект.
  2. Property (Setter) Injection – идеята е подобна на горната, пак инджектваният обект да бъде сетнат на клас пропърти, но не през конструктора, а през сетър.
  3. Method Injection – тук имаме ситуация, подобна на Property (Setter) Injection но с разликата, че основният клас имплементира интерфейс, който го задължава (него, основният) да има метод, който да играе ролята на сетър, и по този начин задължава основният клас да приеме даден обект.
    Например клас Car имплементира интерфейс EngineMountable, в който има метод engine() и по този начин класът Car e длъжен да има инджектнат обект за двигател.
    Добър въпрос би бил, ако Car наследява например абсклас, не може ли в него да е изнесен абстрактен сетер/сетери, които да играят същата роля, тоест вместо интерфейс да имаме абсклас.
    Не съм съвсем наясно с идеята на този тип injection, признавам си. Може би идеята е да се зададе някакъв централизиран начин за инджектване на обекти, ако имаме абсклас, или вероятно ако е интерфейс, да задължи имплементиращите обекти да имат такива „entry points“ за инджектване на обекти…

Inversion of Control (IoC)

Inversion of Control (IoC) е desing principle, която използва DI, при който идеята е части от цялостната функционалност на даден клас, да се „разхвърля“ или разпредели по други класове, с цел да се спази SOLID Single Responsibility Principle и основният клас да бъде олекотен, и след това когато ни трябват тези „разхвърляни“ функционалности, обекти на тези класове да бъдат инджектвани в основният клас.

Taка се постига и high cohesion вътре в класа както и low coupling между отделните класове.

Dependency Inversion Principle (DIP)

Dependency Inversion Principle (DIP) е SOLID принцип, нещо като продължение или разширение на IoC, в смисъл такъв, че повелява основният клас, в който ще инджектваме обектите на класовете, които сме „разхвърляли“, да може да приема като входни параметри не обекти от конкретен клас, а от различни класове, които обаче екстендват или имплементират даден абсклас или интерфейс.
Демек, „дай ми нещо, с което да отвинтя тази гайка, а не конкретен гаечен ключ“…

Идеята и на двата принципа е да се постигне максимално т.н. „loose coupling“ и максимална кохезия вътре в класа. Припомнете си статията „Cohesion and Coupling“.
Но работата е е там, че само с прилагане на IoC не става, демек само IoC не стига за да се постигне това.

Тоест, основният клас сякаш казва предварително: „не искам конкретна функционалност и обект от конкретен клас, давайте ми обекти, които по принцип ще ми свършат работата“, демек имплементиращи даден интерфейс.

Taка постигаме „high-level modules should not depend on low-level modules“.

Защо?
Защото в случая, high-level модулът при нас е основният клас, а low-level са тези, които му инджектваме, които вършат някаква по-конкретна и специфична работа, тоест са по-ниско в нивото на абстракция.
И основният става по-малко зависим от инджектваните, защото може да приема по-широк диапазон от обекти, а не конкретно само от един клас.

Пример: ти си основният клас и искаш да си викнеш (инджектнеш) майстор да ти смени водомера.
Кога си по-малко зависим (бидейки high-level module) от майстора (който е low-level module)? Ако трябва да можеш да викаш само един конкретен майстор или когато можеш да извикаш всеки майстор, стига да имплементира VodoprovodchikInterface?

Общото между тях?

Общото между IoC и DIP е целта – да се намали зависимостта между отделните класове. Например, да не се създава обект от един клас вътре в друг клас, защото така твърдо свързваме двата класа и единият вече не може без другият, конкретно „другият“, то е ясно, че все някакъв обкет трябва да му инджектнеш, освен ако не си му задал default стойност null.

Демек, когато инджектваме обект, да не очакваме параметърът през който го инджектваме да е от конкретен клас, а да е по-общо – от конкретен интерфейс. Така казваме, че инджектваме не конкретна функционалност, а който по принцип прави това, което ни трябва. Без задължително да е обект от този конкретен клас.

Your code gets decoupled so you can easily exchange implementations of an interface with alternative implementations.

Разликата между тях?

Разликата е, че DIP e по-скоро продължение, надстройка на IoC. Демек, IoC повелчва функционалността на един клас да се „разхвърля“ на под-класове, а DIP повелява това разхвърляне да стане така, че „разхвърляният“ клас да може да приема не конкретни функционалноти, а функционалности по принцип.

Литература:

https://www.tutorialsteacher.com/ioc/introduction

https://www.tutorialsteacher.com/ioc/dependency-inversion-principle

https://www.tutorialsteacher.com/ioc/dependency-injection

Tight coupling and Loose coupling

Един добър пример за loose coupling е например, ако хвърля топка към някого за да я хване. Интересува ме той да я хване, не ми трябва да знам на колко години е, какво е закусвал тази сутрин и т.н… Щом просто свършим работата, колкото и по-малко да знаем един за друг, ето това е loose coupling.

Един пример за tight coupling и даже по-скоро за rigid and fragile код:

class CustomerRepository
{
    private Database $database;     

    public function __construct(Database $database)
    {
        $this->database = $database;
    }

    public function Add(string $tableName, string $customerName) : void
    {
        $this->database->AddRow('John Doe', $customerName);
    }
}

class Database
{
    public function AddRow(string $table, string $value) : void 
    {
        //...
    } 
}

Показаният код е реално напълно редовен, но проблемът може да се види в перспектива, защото ако променим нещо в AddRow() методът на класа Database, това би счупило използването му в CustomerRepository->Add().
Каквото и да било, поредноста на аргументите, типовете на съответните им параметри…

Демек, хвърлям ти топката но дали ще я хванеш…
За да съм сигурен, че ще я хванеш, ще те задължа да имаш съответният метод, със съответният signature.

Добър пример за това как да превърнем горният пример от tight coupled в loose coupled, би бил например да задължим с интерфейс методът AddRow на класа Database да спазва зададен signature.

class CustomerRepository
{
    private IDatabase $database;     

    public function __construct(IDatabase $database)
    {
        $this->database = $database;
    }

    public function Add(string $tableName, string $customerName) : void
    {
        $this->database->AddRow('John Doe', $customerName);
    }
}

interface IDatabase
{
    public function AddRow(string $table, string $value) : void;
}

class Database implements IDatabase
{
    public function AddRow(string $table, string $value) : void 
    {
        //...
    }
}

Можем да си направим извод, че loose coupling не значи непременно по-голяма либералност, а както се вижда в случая – даже обратното. По-скоро стандартизация, защото така премахваме опасността от различни разновидности (по signature например) на методът AddRow()

Демек, от Add() на CustomerRepository викаме директно AddRow() на Database, но той е длъжен да спазва сигнъчъра на интерфейса IDatabase. Като с цел взаимозаменяемост, той може да има различни имплементации.

Друг пример за това как можем да опростяваме нещата и да ги направим по-гъвкави и взаимозаменяеми.
Например имаме близки като функционалност неща, и за отделните от тях правим отделни, независими класове и съответно, викаме когато който ни трябва.
Вместо това можем пак да имаме отделни класове, но имплементиращи общ интерфейс.

class DiscOperations
{
    public function doDiscWrite(string $data) : bool
    {
        //...
    }
}

class DVDOperations
{
    public function doDVDWrite(string $data) : bool
    {
        //...
    }
}

if (WRITE2DISC) {
    (new DiscOperations)->doDiscWrite($someData);
} else {
    (new DVDOperations)->doDVDWrite($someData);
}

Не би ли по-унифицирано ако например…

interface StorageOperations
{
    public function write(string $data) : bool;
}

class DiscOperations implements StorageOperations
{
    public function write(string $data) : bool
    {
        //...
    } 
} 

class DVDOperations implements StorageOperations
{
    public function write(string $data) : bool
    {
        //...
    }
}

$operator = WRITE2DISC ? new DiscOperations : new DVDOperations;

$operator->write($someData);

Защо? Защото най-малкото можем да си напишем много подобни Оператори, който ще са лесно заменими.

UML диаграми и видове отношения между класовете

Association – чисто семантична връзка от например тип HAS-A, например доктор има пациенти и т.н… Програмно може например да се реализира като един клас Доктор има едно или повече пропъртита – обекти от клас Пациент.

Dependency – тук имаме директна зависимост между различни елементи, които не могат да съществуват един без друг. Например наследяване на класове, имплементиране на интерфейси… Този тип отношение може да се раздели на две: specification и generalization.

Aggregation – тук имаме отношение на отделни елементи, които в случая са част от дадена цялостна система, но също така могат и да съществуват свободно и извън нея (системата). Добър пример – птица и ято. Ятото се състои от птици, но отделните птици са си птици и без ятото. Или държави, участващи в дадена международна организация като например Европейски Съюз. Всяка може да съществъва сама по себе си.

Има и разновидност на aggregation наречена AcquaintanceAcquaintance is a weaker relationship than aggregation and suggests much looser coupling between objects.

Composition – отношение parent – child, като например Orders – OrderItems. Децата не могат да съществуват и нямат смисъл без родителя. Изчезне ли едното, изчезва(т) и дугото(другите). Добър пример – стаи и сграда. Ако разрушим сградата, няма как да имаме нейните стаи.

Друга важна концепция е т.н. Multiplicity – концепция, която допълва семантичните зависимости между отделните обекти в дадената система, с количествени характеристики. Това означава, че можем допълнително да опишем и количествените ограничения върху дадените семантични отношения.

Литература:

https://www.uml-diagrams.org/

https://www.guru99.com/uml-relationships-with-example.html

http://10minbasics.com/uml-essentials-in-10-minutes/

Operator polymorphism

Полиморфизъм, основан на това, че една и съща операция от чисто семантична гледна точка (а не математическа), може да извършва различни действия и да създава различен краeн резултат, в зависимост от операндите.

Например под операцията събиране може се има предвид конкатениране на стрингове ако подaдем стрингове, може да знaчи аритметическо събиране ако имаме числа… и т.н…

Затова казвамe, че се има предвид семантичнният смисъл на операцията, а не чисто математическият.

Добър пример за Operator polymorphism е например Ad hoc polymorphism, по-известен като function overloading.
Koeто означа, че следователно можем да причислим Operator polymorphism към Static polymorphism.

Robustness principle

Известен също и като Arrow rule или Postel’s law.

Можем да заменим метод от родителски обект, с метод от наследник, ако методът на наследника е по-либерален откъм входни параметри, и по-консервативен откъм изходен резултат.

Но не и обратното.

Be conservative in what you do, be liberal in what you accept from others.

Литература:

https://en.wikipedia.org/wiki/Robustness_principle

https://medium.com/kubo/postels-law-designing-for-robustness-1503ff1f72dd

Static and dynamic polymorphism

Още са известни като Compile time polymorphism (static binding) и Runtime polymorphism (dynamic/late binding).

Това са видове полиморфизъм според това КОГА се случват, демек compile time или runtime. В какъв смисъл? В смисъл кога изпълнението на програмата ще извика по даден сигнъчър на функцията – един код, кога друг.

Динамичните – runtime, a Статичните – compiletime.

Даже по-правилно е Static polymorphism да бъде наричан Static binding, и съответно Dynamic polymorphism – Dynamic binding.

Но какво изобщо е binding?
The process of replacement of the method call with method definition is called as binding.
Или още – като извикаме функция с дадено име, параметри и тип на резултата, коя точно функция да извикаме и изпълним.
Binding е „връзката“ между извикването и дефиницията, или по-точно, като извикаме това и това, кой код реално ще се изпълни.

Например Ad hoc (или още Overloading) се случва compile time, защото тогава програмата решава коя от всички функции с еднакво име, ще бъде извикана runtime, на база на подадените аргументи. Демек – ясно се вижда – при даден сигнъчър какво да се изпълнява. Затова е Static binding или oще Static polymorphism.
The compiler looks at the method signature and decides which method to invoke for a particular method call at compile time.

Compile time polymorphism (static binding) and Runtime polymorphism (dynamic binding). Method overloading is an example of static polymorphism, while method overriding is an example of dynamic polymorphism.

Dynamic binding (Dynamic polymorphism) имаме например при оверрайдване на методи:

class SomeParent
{
    public function sayHello(): void
    {
        echo 'I am parent';
    }
}

class SomeChild extends SomeParent
{
    public function sayHello(): void
    {
        echo 'I am child';
    }
}

(new SomeParent)->sayHello();    // I am parent
(new SomeChild)->sayHello();     // I am child

Защо имаме динамичен, а не статичен? Не е ли и в този пример зададено още compiletime кога кой метод да извика?
Защото тънкостта е, че като имаме оверрайдване все едно казваме на самият компилатор „за този метод, имам версия тук, имам версия там… коя ще ми трябва, още не знам“. Самата идея на оверрайдването е такава – да НЕ се знае предварително коя точно „версия“ на метода ще ни трябва.

Ще попитате, „добре де, така написано, компилаторът не му ли става ясно кога кой метод да извика?“
Явно не, защото докато не инстанцираме обектите, което става runtime, няма как да знаем кой точно да извикаме. Демек, той методът е един, не са два или повече, просто няма как да направим самата връзка между извикването и това кое да извикаме, докато нямаме обект-викач, който да го извика.
The version of a method that is executed will be determined by the object that is used to invoke it.
Докато няма родителски и детски обекти, няма как да знаем чия „версия“ на метода да извикаме.

method overloading is an example of compile time/static polymorphism because method binding between method call and method definition happens at compile time and it depends on the reference of the class (reference created at compile time and goes to stack).

method overriding is an example of run time/dynamic polymorphism because method binding between method call and method definition happens at run time and it depends on the object of the class (object created at runtime and goes to the heap).

Method Overloading is an example of static polymorphism.
Method Overriding is an example of dynamic polymorphism.

Static Polymorphism achieved through static binding.
Dynamic Polymorphism achieved through dynamic binding.

Static Polymorphism happens in the same class.
Dynamic Polymorphism happens between different classes.

Object assignment is not required for static polymorphism.
It is required where a subclass object is assigned to super class object for dynamic polymorphism.

Inheritance not involved for static polymorphism.
Inheritance involved for dynamic polymorphism.

Работата е там, че при оверлоудване имаме съвсем различни функции/методи но с ЕДНО ИМЕ.

При оверрайдване имаме ЕДНА функция/метод, в отделни наследяващи се класове, но просто все още не сме решили коя от тях да извикаме. А ще решим на база това кой от класовете инстанцираме или използваме статично. Демек, няма как предварително, при компилиране, компилаторът да знае коя версия на тази ЕДНА функция ще извикаме.

Демек, при оверлоудване предварително, на база сигначъра казваме на компилатора „може тази функция/метод да се казва винаги еднакво, но ако я извикаш с тези и тези аргументи и тип резултат – извикваш тази, ако я извикаш с тези и тези аргументи и тип резултат – извикваш онази.“ На база различният сигнъчър, дори и имената да са еднакви, компилаторът знае коя кое да извика предварително.
Всичко е ясно зададено предварително. На база сигнъчър.

Не е така с оверрайдването. Там коя точно версия на функцията/метода ще се извика, се случва рънтайм.

Демек, при оверрайдването идеята е да предоставим предварително N на брой „версии“ на даден метод, но чак рънтайм да решим коя точно да извикаме. Демек, байндингът да стане динамично.

Литература:

https://stackoverflow.com/questions/20783266/what-is-the-difference-between-dynamic-and-static-polymorphism-in-java

https://www.sitepoint.com/quick-guide-to-polymorphism-in-java/

https://en.wikipedia.org/wiki/Method_overriding

Subtype polymorphism

Още известен като Inclusion Polymorphism – ако имаме клас А, който бива наследен от клас B, то обекти от клас B могат да бъдат използвани вместо такива от клас А, стига разбира се да не са private.

Важи също и за примитивните типове като например int и float. Долният пример на PHP e валиден, защото int се явява като подтип на float:

function patapan(float $a) { }

patapan(123);

Да си спомним за т.н. Numeric tower – йерархично подредени числени типове. В PHP откъм числени типове имаме само Integer и Float. Float e програмният (или компютърният) начин за съхранение на рационални числа (Rational), разликата е, че по дефиниция, от математическа гледна точка рационалните числа могат да бъдат безкрайни дроби (напр. 1/3 е 0.333333…), а float’s трябва да могат все пак да съхранят тази безкрайна дроб с известно закръгляне и загуба на точност.

Type safety

Един език се приема за type safe ако самият език (компилатор, интерпретатор) следи за спазване на правилните типове на стойностите, присвоявани нa променливите и на връщаните резултати, според това как са зададени програмно, демек още на ниво компилация.

Както и след това, по време на изпълнение, дали не се опитваме да изпълним операция с променливи с несъвместими стойности, като например да съберем integer със string и т.н…
Виж, integer с boolean може винаги, просто явно идеята е, че PHP винаги ще направи каквото може за да тайпкастне, само и само да извърши операцията.

Стига да е възможно, демек string ‘hello’ не може да се тайпкастне към integer 20, но ’20hello’ може да се тайпкастне към integer 20.

Type safety-то поне на PHP, има четири аспекта:

1) Дали можеш динамично да променяш типа на дадена променлива, задавайки и стойности от разлилчен тип динамично (runtime).

2) Дали можеш да извършваш операции с променливи от различен тип, като имаме предвид, че PHP ще направи каквото може да тайпкастне стойностите според оператора, само и само да изпълни операцията.

3) Дали можем да достъпим недекларирана променлива:

echo $c;

ще доведе до: Warning: Undefined variable $c in…

4) Дали можем да достъпим несъществуващ елемент на масив:

$d = array('hello', 'world');
echo $d[21];

ще получим: Warning: Undefined array key 21 in…

Важно да се прави разликата между static/dynamic и strong/weak. Първото е по отношение на задаването на стойности, второто – по операциите, които извършваме с тях.

PHP може да се счита за dynamically typed, както и strong typed език, защото можеш за даден променлива, да и задаваш динамично (runtime) стойности от различен тип, демек, да и сменяш типа.

Но не и примерно да събираш различни типове (не забравяме все пак, че PHP ще направи каквото може да тайпкастне стойностите според оператора, само и само да изпълни операцията).

Пример за dynamic typing, който е ОК в PHP и с който сменяме типа на променливата:

$a = true;
$a = 10;

Toва е идеята на dynamically typed за разлика от static typed – динамично да можеш да сменяш типа на дадената променлива, освен ако изрично не си и го задал.

При static typing зададен ли е изрично типът – край.

А strong typing, за разлика от weak typing значи вече когато извършваме операции с дадените променливи, дали не се опитваме да изпълним операция с променливи с несъвместими стойности, като например да съберем boolean с integer…

Ако опитаме да умножим boolean с integer,

$a = 123;
$b = true;
echo $a + $b;

ще доведе до:
Fatal error: Uncaught TypeError: Unsupported operand types: boolean + int …

Closures are a poor man’s object

Има се предвид, че клоужърите и ламбдите имайки свой скоуп на променливите, могат да извършват т.н. „data hiding“, тоест да „скриват“ и капсулират информацията от околният свят в себе си.

Aко погледнем следният пример, ще видим че даденият клоужър bloa() може да има свои, частни променливи, които не са достъпни отвън.

<?php
$patapan = function(string $s): string {
    return strtoupper($s);
};

$bloa = function($a) use ($patapan): string {
    $prom1 = 'Super!';
    return $patapan($a);
};

$strings = ["apple", "orange", "banana", "coconut"];
$upprs = array_map($bloa, $strings);

var_dump($upprs);  // Dumps the uppercased array
var_dump($prom1);  // Undefined variable $prom1 in…
echo $patapan('Good question');  // GOOD QUESTION

Какво излиза на практика? Че closures и lambdas си приличат с обектите, по това, че предлагат свой скоуп и правят data hiding. Moже би затова се казва, че са „the poor man objects“.

Coercion polymorphism

Нека първо си припомним какво е Implicit type casting в PHP.

<?php
declare(strict_types = 1);

$x = '25';
var_dump($x);       // string(2) "25"
var_dump($x * 2);   // int(50)

Виждаме как PHP сам е извършил type cast към integer за да изпълни аритметичната операция.

Explicit type casting е зададен програмно от нас, когато сами кастваме променлива към друг тип.

При Coercion polymorphism можем да използваме и двата вида type casting, като например с помоща на вторият вид (explicit), може например да кастваме връщаният резултат.

PHP поддържа Coercion polymorphism само ако зададем declare(strict_types = 0); за да разрешим на PHP функциите да приемат аргументи от различен от зададеният тип.

<?php

class SomeClass
{
    private int $a;

    public function setA(int $a): void
    {
        $this->a = $a;
        var_dump($this->a);
    }
}

$p = new SomeClass;
$p->setA(123);      // int(123)
$p->setA(123.45);   // int(123)

Ясно се вижда идеята на тoзи вид полиморфизъм – PHP сам, имплицитно преобразува подаденият аргумент и по този начин можем да използваме въпросният метод както с целочислени, така и с дробни аргументи.

Parametric polymorphism

Логиката на функцията трябва да се задава с това, какви типове аргументи и подаваме, а не да я override-ваме или overload-ваме (второто е друг тип полиморфизъм – Ad hoc).

За разлика от Ad hoc полиморфизмът, където имаме същата функция, пренаписана (overloaded) повече пъти, според това какъв тип аргументи и подаваме.

Примерно, ако не задаваш типа на входните параметри, както до скоро беше по принцип в PHP, можеш да използваш една и съща функция за например събиране на числа или конкатениране на стрингове…
Това е особено лесно например в JavaScript, където операторът „+“ служи и за двете.
Но това не е са добри примери за Parametric Polymorphism, защото изискването е да се спазва т.н. type safety.

… parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety

Идеята на Parametric Polymorphism НЕ Е да имаме пълна либералност на това, какво подаваме като тип на параметрите, а по-скоро да разширим областта от възможни типове но така, че логиката вътре във функцията да е една и съща без значение какъв конкретно тип параметри подаваме. Под „да разширим“ се има предвид, да имаме т.н. ковариантност на входните типове.

Toест, не да можем да подаваме каквото си искаме, това би било т.н. Ad hoc plymorphism, което си е едно към едно overloading.
Following Christopher Strachey, parametric polymorphism may be contrasted with ad hoc polymorphism, in which a single polymorphic function can have a number of distinct and potentially heterogeneous implementations depending on the type of argument(s) to which it is applied. 

Защото това например НЕ Е Parametric Polymorphism:

function add($a, $b)
{
    if ((gettype($a) === 'string') && (gettype($b) === 'string')) {
        return $a . $b;
    }
    if ((gettype($a) === 'integer') && (gettype($b) === 'integer')) {
        return $a + $b;
    }
}

Нито пък това, което би било Ad hoc и го давам като неработещ пример, защото както знаем в PHP оверлоудване не се поддържа:

function add(int $a, int $b): int
{
    return $a + $b;
}

function add(string $a, string $b): string
{
    return $a . $b;
}

За PHP специално, добър пример би бил използването на SOLID принципът Dependency Inversion, при който изискваме абстракция, а не конкретна функционалност за тип на входен параметър. Тоест, подаваме на една функция различни обекти но от един и същ интерфейс или абстрактен клас, и тези подадени обекти съответно правейки различни неща, определят поведението на функцията.

interface CacheableInterface
{
    public function getCacheKey(): string;
}

class ProductClass implements CacheableInterface
{
    public function getCacheKey(string $id): string
    {
        return 'product_' . $id;
    }
}

class CategoryClass implements CacheableInterface
{
    public function getCacheKey(string $id): string
    {
        return 'category_' . $id;
    }
}

function store(CacheableInterface $cacheable): string
{
    return $cacheable->getCacheKey('ABC-120-3G');
}

Вижда се как на store() може да подаваме различни обекти, стига да са от интерфейс CacheableInterface и съответно, тези отделни обекти имат свое виждане за това, което извеждат. От там идва и различното поведение на store()

Друго, което можем да забележим, че Parametric Polymorphism доста прилича на Subtype Polymorphism, защото горният пример би бил добър и за Subtype Polymorphism ако имахме и йерархия от класове.

Добър въпрос би бил, каква е разликата между Parametric Plymorphism и Subtype Polymorphism?

При Subtype Plymorphism трябва да имаме йерархия на типовете, например на класовете или на примитивните типове (float, int…).

При Parametric Polymorphism – не. Както се вижда от горният пример, няма йерархия между взаимозаменяемите ProductClass и CategoryClass, между тях самите, нищо че имплементират общ интерфейс.

Затова Parametric Polymorphism е по-общият случай на Subtype Polymorphism.

Литература:

https://sergeyzhuk.me/2017/04/09/oop-polymorphism/

https://en.wikipedia.org/wiki/Parametric_polymorphism

Inclusion plymorphism

Същият като Subtyping Polymorphism – ако имаме клас А, който бива наследен от клас B, то обекти от клас B могат да бъдат използвани вместо такива от клас А.

Както и, можем вместо float да използваме int.

Става въпрос за типовете на подаваните аргументи.

Lazy loading

There are four common ways of implementing the lazy load design pattern:

  1. Lazy initialization (synonym for Lazy instantiation)
  2. Virtual proxy
  3. Ghost
  4. Value holder

1. Lazy initialization

Чак когато инстанция на даден обект ни потрябва, тогава го инстанцираме.

2. Virtual proxy

Virtual Proxy is an object with the same interface as the real object. The first time one of its methods are called it loads the real object and then delegates.

Създаваме 2 обекта, от 2 отделни класа, имплементиращи 1 общ интерфейс.
Когато извикаме някой метод от ПЪРВИЯ обект, той създава обект от ВТОРИЯ клас, присвоява го на пропърти от ПЪРВИЯТ, и ОТ ТУК НАТАТЪК каквото искаме да достъпим от ВТОРИЯ, викаме („минаваме“) през ПЪРВИЯ.

A virtual proxy object shares an interface with the „real“ object. The first time a property of the virtual proxy is accessed, the real object gets initialized. From that point on, accessing properties of the virtual object returns the corresponding property of the real object.

Явно идеята е ако оригиналният обект е ресурсоемък или времеемък, но трябва да го инициализираме по една или друга причина, да не го инициализираме него, а някакъв друг, виртуален, който има същият интерфейс, и чак когато ни трябва оригиналът, тогава във виртуалният създаваме оригиналният, и с делегиране го използваме (delegation).

3. Ghost

A „ghost“ is the object that is to be loaded in a partial state. It may only contain the object’s identifier, but it loads its own data the first time one of its properties is accessed. For example, consider that a user is about to request content via an online form. At the time of creation all we know is that content will be accessed but what action or content is unknown.

ghost is the real object without any data. The first time you call a method the ghost loads the full data into its fields.

Или с други думи, създаваме обект но съвсем опростен с идеята в последвие да добавяме към него повече данни. Добър пример би бил, ако първо създадем някакъв „полупразен“ обект, в който ще съхраняваме и обработваме информация от събмитната HTML форма, но го „пълним“ след събмитване.

$userData = array(
    "UID" = > uniqid(),
    "requestTime" => microtime(true),
    "dataType" => "",
    "request" => ""
);

if (isset($ _POST['data']) && $userData) {
    // …
}

4. Value holder

Basically, а value holder is a generic object that handles the lazy loading behavior and appears in place of the object’s data fields. When the user needs to access it, they simply ask the value holder for its value by calling the GetValue method. At that time (and only then), the value gets loaded from a database or from a service (this is not always needed).

Най просто, идеята е когато имаме нужда от дадено пропърти на даден обект, и това е свързано с ресурсоемка или времеемка операция (извличане от БД например), това извличане да стане чак тогава, през даден гетър например, в който например може да има допълнителна логика, която да запази тази информация в статично пропърти, за да не се извлича всеки път.

public function getValue($parameter) {
    if (self::$value == null) {
        self::$value = valueRetrieval($parameter);
    }
    return self::$value;
}

Литература:

https://en.wikipedia.org/wiki/Lazy_loading

https://en.wikipedia.org/wiki/Lazy_initialization#PHP

https://www.geeksforgeeks.org/lazy-loading-design-pattern/

Primitive Obsession code smell

Има случаи, в които е по-добре да използваме обекти вместо примитивни типове. Нека погледнем следният пример:

Имаме клас User в който подаваме дадено пропърти, например $url като стринг и също, преди да го сетнем, правим някаква примерна валидация.

class User
{
    private string $url;

    public function setUserUrl(string $url) : void
    {
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
            throw new SomeValidationException('Wrong url bla bla bla...');
        }
        $this->url = $url;
    }

    public function getUserUrl() : string
    {
        return $this->url;
    }

    // ...
}

На пръв поглед всичко е доста просто.

Но първото, което не е ОК, е че валидацията на URL-a e в класа User. Не нарушаваме ли Sigle Responsibility SOLID принципът?

Също, ако трябва да подадем URL и на друг клас, там също трябва да я има тази валидация – повтаряне на код.

Да не говорим, че ако подаваме така, по отделно, може да имаме „експлозия от входни параметри“ ако се наложи да подаваме и други стойности.

Няма ли да е по-елегантно и гъвкаво ако създадем нов клас Url и там да изнесем валидирането и евентуално друга логика, свързана с Url-и. И където ни трябва, просто да инджектваме обект от класа Url?
T.н. „Replace Data Value with Object “ техника за рефакториране.

class User
{
    private string $url;

    public function setUserUrl(Url $url) : void
    {
        $this->url = $url;
    }

    public function getUserUrl() : string
    {
        return $this->url->getUrlAddress();
    }

    // ...
}

class Url
{
    private string $url;

    public function __construct(string $url)
    {
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
            throw new SomeValidationException('Wrong url bla bla bla...');
        }
        $this->url = $url;
    }

    public function getUrlAddress() : string
    {
        return $this->url;
    }

    // ...
}

Вижда се, че Primitive Obsession трябва да се избягва, когато не просто използваме примитивни типове за някаква стойност, но трябва и да имаме някаква логика, на която тези примитивни стойности да се подчиняват.

Добър пример би бил ако например искаме да имаме пропърти $age за даден User, но също и трябва да я използваме тази възраст само за живи хора, а не и за например исторически личности, за които възрастта може да е стотици години.
Тогава не може просто да подаваме произволен, положителен integer.

Литература:

https://dzone.com/articles/code-quality-fighting-primitive-obsession-code-sme-1

Information hiding

Какво да крием?
Пропъртита на класа (данните на обекта).

Как да ги скрием?
Като ги зададем с видимост private или protected и ги достъпваме през сетъри и гетъри.

Защо да ги крием?
За да предотвратим възможността от това да бъдат директно и безконтролно достъпвани. Затова са и гореспоменатите сетъри и гетъри – за да зададем допълнителна логика за достъпване на въпросните пропъртита (данни на класа).

Литература:

Aspect-oriented programming

Най-просто – когато имаме допълнителни (така да се каже „сервизни“), класове, които не са част от самият бизнес модел, но са необходими (като Logger, Auth…), вместо да ги инджектваме в съответният съществен клас (напр. News) и така да го натоварваме, и него, и другите съществените (бизнес модела) с още код, правим допълнителни Aspect класове като напр. AspectLogger, който ще прави логването като Logger, и допълнително AspectConfigurator, където задаваме кой „аспект клас“ къде да бъде викан.

Ето един супер прост пример – на този клас искаме да му добавим например проверка дали даденият, логнат потребител има право да го използва.

Стандартният начин е да имаме клас Auth например, и да инджектнем един негов обект, и например в началото на всеки метод да викаме метод на Auth който да проверява.

<?php
class MyServices
{
    public function doAdminStuff1() {
        //some stuff only the admin should do
        echo "Calling doAdminStuff1";
    }

    public function doAdminStuff2() {
        //some stuff only the admin should do
        echo "Calling doAdminStuff2";
     }
}

Няма ли това да усложни нещата? Ами утре ако трябва и друга функционалност да се използва вътре в MyServices? Пак инджектвай, пак усложнявай методите на MyServices…? И то с какво? С нещо, което няма пряка връзка с MyServices.

Или да изнесем например Auth функционалността извън MyServices? ОК, но това ще значи навсякъде, където се викат методи на MyServices, да използваме Auth и другите (Logger…).

Няма ли да е по-елегантно да изведем някъде настрана логиката кога, къде и какво да се вика за проверки, логове и т.н., без да занимаваме съществените за бизнес модела класове?

AOP is a PECL extension that enables you to use Aspect Oriented Programming in PHP. Като гледам, тук най-просто се дефинират нещо като евент хендлъри, където се задава за кой клас, кой метод, и кога да се извика какво.

<?php
aop_add_before('MyServices->doAdminStuff1()', 'theNameOfTheAuthCheckMetod');

In computingaspect-oriented software development (AOSD) is a software development technology that seeks new modularizations of software systems in order to isolate secondary or supporting functions from the main program’s business logic.
It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a „pointcut“ specification.

Core concerns – неща, директно свързани с бизнес модела.

Cross-cutting concern – така да се каже „помощни неща“ като например логване на грешки, аутентикация… Именно това е целта и идеята на Aspect Orienter Programming – да капсулира тези cross cutting concerns в т.н. „aspects“ и да направи използването им възможно, с цел да се олекоти core concern. Aspect-oriented programming aims to encapsulate cross-cutting concerns into aspects to retain modularity.

For instance, if writing an application for handling medical records, the indexing of such records is a core concern, while logging a history of changes to the record database or user database, or an authentication system, would be cross-cutting concerns since they interact with more parts of the program.

Aspects – част от целият софтуер, който може да се използва на различни места, но не е директно свързан с „program’s primary function“.
Но ако гледаме по-философски на нещата, дори и самата бизнес логика (the core concern) може да се разглежда като aspect, and by weaving them together (a process also called composition), one finally produces a whole out of the separate aspects.

Литература

https://en.wikipedia.org/wiki/Aspect-oriented_programming

https://aop-php.github.io/

https://en.wikipedia.org/wiki/Aspect-oriented_software_development

Cohesion and Coupling

Cohesion is the indication of the relationship within a class.

Coupling is the indication of the relationships between classes.

Кохезията трябва да е максимално висока, защото тя характеризира колко един клас прави само това, което трябва да прави, т.е. до колко отговаря на Single Responsibility Principle. Ниската кохезия означава, че класът се опитва да е „швейцарско ножче“, или т.н. „God class“.

Coupling-ът между класовете трябва да е минимална, защото тя характеризира до колко те за зависими и до колко промяна в единият може да счупи останлите.

За да има low coupling между класовете, една добра идея е да се правят така, че да се разбира лесно какво правят поотделно, без да се знае много или даже нищо за цялата система.

Трябва да бягаме от това да се опитваме да правим т.н. „God class“ или „Swiss army knife“…

Литература:

https://ducmanhphan.github.io/2019-03-23-Coupling-and-Cohension-in-OOP/

https://stackoverflow.com/questions/3085285/difference-between-cohesion-and-coupling

Dynamic type vs. Static type language

Dynamic type – задава (а също и променя) типа на променливата runtime – по време на изпълнение. Тоест – променливите динамично задават типа на променливата при присвояване.

Static type – по време на компилация се задава коя променлива какъв тип данни може да приема. Веднъж зададен типът на променливата, тя не може да съдържа стойност от друг тип.

First class citizen

Можеш ли да го подаваш като аргумент?

Можеш ли да го използваш като return на функция?

Можеш ли да му задаваш стойност?

Можеш ли да го задаваш като стойност на друга променлива?

Простите, скаларни променливи са винаги FCC.

Но не само скаларни променливи, функциите могат да бъдат FCC, защото могат да бъдат предавани като аргументи на други функции (callback фунции напр.) или връщани като резултат от други функции.

function po_dve(int $a): int
{
    return $a * 2;
}

function po_tri(int $a): int
{
    return po_dve($a);
}

echo po_tri(5);    //   10
function patapan(): string
{
    return 'Hello';
}

function matapan(string $patapan): string
{
    return $patapan . ' ' . 'world';
}

echo matapan(patapan());    // Hello world

Process vs. Thread

Процесите са напълно отделни един от друг, не шерват ресурси, могат да бъдат килвани напълно независимо един от друг.

Процесите комуникират помежду си с механизъм, наречен Inter Process Communication (IPC),
а нишките – с глобални за процеса, променливи, защото споделят общото адресно пространство на процеса.

Процесите са все едно отделнте програми, нишките са дадената програма, разделена на части с оглед на по-оптимално изпълнение на цялата задача, по-оптимално използване на машинните ресурси.

Subroutines

Стриктно погледнато, истинското, научно име за функциите е „subroutine“ или „routine“, a на български – „подпрограми“.

Набори или поредици от програмни инструкции, групирани логически така, че да извършат своята определена част от общата функционалност на цялата програма. Но трябва да са именовани по някакъв начин. Защото иначе един ред или купчина редове код, сами по себе си, ако не са именовани с име и изобщо – signature, не могат да се нарекат subroutine, защото са на практика – неизползваеми. Как да ги извикаш пак? Как да им подадеш аргументи?

Много важно, макар и не задължително (по-скоро признак на добър стил) е дадената подпрограма да извършва само дадена, тясно специализирана дейност, а не да е колкото се може по универсална. По-добре да имаме много на брой подпрограми, но всяка вършеща само конкретна част от цялата програма, отколкото обратното.

А вече отделно тези подпрограми биват:

  • функции – трябва да върне резултат;
  • процедура – извършва обработка върху подаден параметър/параметри или глобален обект, без да има нужда да връща резултат;
  • метод – процедура или функция, принадлежаща на даден клас;

vCard

vCard е текстов формат за обмен на електрони визитни картички. Файлът vCard се състои от записи от типа vCard, всеки от който съдържа информация за една визитна картичка. Записът vCard може да съдържа име, адрес, номера на телефони, URL, лого (логотип), видео и аудио фрагменти и др.

Обикновено файлът vCard има разширение *.vcf и mime type – text/vcard

Форматът vCard (произлиза от Versitcard), е разработен през 1995 г. от консорциума Versit, в който са влизали Apple ComputerAT&T (по-късно Lucent), IBM и Siemens. През декември 1996 г. всички права върху формата преминават към Internet Mail Consortium.

Версия 2.1 получава поддръжка в повечето от пощенските клиенти. Версията 3.0 в описана в RFC 2425 и RFC 2426.

Използват се например за атачване към e-mail писма, MMS съобщения, могат да се кодират като QR кодове и др…

Пример:

BEGIN:VCARD
VERSION:3.0
FN:к.м.н., проф. Иван Иванов Ивановски
N:Ивановски;Иван;Иванов;проф., к.м.н.
ORG:Здраве и живот
URL:http://bg.wikipedia.org/Иван Ивановски
EMAIL;TYPE=INTERNET:ivanovski@example.com
END:VCARD

xCard – vCard има формат за XML, наречен xCard или „vCard XML Representation“.

<?xml version="1.0" encoding="UTF-8"?>
<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0">
  <vcard>
    <n>
      <surname>Gump</surname>
      <given>Forrest</given>
      <additional/>
      <prefix>Mr.</prefix>
      <suffix/>
    </n>
    <fn>
      <text>Forrest Gump</text>
    </fn>
    <org>
      <text>Bubba Gump Shrimp Co.</text>
    </org>
    <title>
      <text>Shrimp Man</text>
    </title>
    <photo>
      <parameters>
        <mediatype>
          <text>image/gif</text>
        </mediatype>
      </parameters>
      <uri>http://www.example.com/dir_photos/my_photo.gif</uri>
    </photo>
    <tel>
      <parameters>
        <type>
          <text>work</text>
          <text>voice</text>
        </type>
      </parameters>
      <uri>tel:+1-111-555-1212</uri>
    </tel>
    <tel>
      <parameters>
        <type>
          <text>home</text>
          <text>voice</text>
        </type>
      </parameters>
      <uri>tel:+1-404-555-1212</uri>
    </tel>
    <adr>
      <parameters>
        <label>
          <text>100 Waters Edge
Baytown, LA 30314
United States of America</text>
        </label>
        <type>
          <text>work</text>
        </type>
        <pref>
          <integer>1</integer>
        </pref>
      </parameters>
      <pobox/>
      <ext/>
      <street>100 Waters Edge</street>
      <locality>Baytown</locality>
      <region>LA</region>
      <code>30314</code>
      <country>United States of America</country>
    </adr>
    <adr>
      <parameters>
        <label>
          <text>42 Plantation St.
Baytown, LA 30314
United States of America</text>
        </label>
        <type>
          <text>home</text>
        </type>
      </parameters>
      <pobox/>
      <ext/>
      <street>42 Plantation St.</street>
      <locality>Baytown</locality>
      <region>LA</region>
      <code>30314</code>
      <country>United States of America</country>
    </adr>
    <email>
      <text>forrestgump@example.com</text>
    </email>
    <rev>
      <timestamp>20080424T195243Z</timestamp>
    </rev>
  </vcard>
</vcards>

jCard – има също и JSON разновидност, наречена jCard или  „The JSON Format for vCard“.

["vcard",
  [
    ["version", {}, "text", "4.0"],
    ["n", {}, "text", ["Gump", "Forrest", "", "Mr.", ""]],
    ["fn", {}, "text", "Forrest Gump"],
    ["org", {}, "text", "Bubba Gump Shrimp Co."],
    ["title", {} ,"text", "Shrimp Man"],
    ["photo", {"mediatype":"image/gif"}, "uri", "http://www.example.com/dir_photos/my_photo.gif"],
    ["tel", {"type":["work", "voice"]}, "uri", "tel:+1-111-555-1212"],
    ["tel", {"type":["home", "voice"]}, "uri", "tel:+1-404-555-1212"],
    ["adr",
      {"label":"100 Waters Edge\nBaytown, LA 30314\nUnited States of America", "type":"work", "pref":"1"},
      "text",
      ["", "", "100 Waters Edge", "Baytown", "LA", "50505", "United States of America"]
    ],
    ["adr",
      {"label":"42 Plantation St.\nBaytown, LA 30314\nUnited States of America", "type":"home"},
      "text",
      ["", "", "42 Plantation St.", "Baytown", "LA", "30314", "United States of America"]
    ],
    ["email", {}, "text", "forrestgump@example.com"],
    ["rev", {}, "timestamp", "2008-04-24T19:52:43Z"]
  ]
]

hCard – стандарт за форматиране на vCard информацията с HTML тагове, във вид, подходящ за вграждане в HTML страници.

Различните смартфони например могатда експортират и импортират контактите си като *.vcf файл с примерен формат:

BEGIN:VCARD
VERSION:2.1
N:;FiBank Contact;;;
FN:FiBank Contact
TEL;CELL;PREF:080012012
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=20=20=20=20=20=20=20=20=20=D0=9C=D0=B0=D0=B9=D0=BA=D0=B0;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=9C=D0=B0=D0=B9=D0=BA=D0=B0
TEL;CELL;PREF:+359887801663
END:VCARD

Null pointer

Null pointer – някаква служебна стойност, която показва, че даденият пойнтер не сочи на никъде.

А null pointer has a value reserved for indicating that the pointer does not refer to a valid object.

Защото има и нещо, наречено „uninitialized variable“, демек, когато променлива е декларирана, но няма стойност. 

И явно в двата случая самият език сетва някакви служебни стойности. И от там идва опасността да се използват такива променливи – едната пойнтър, дето не сочи към нищо, другата обикновена променлива, дето не съдържа нищо.

Графи и цикломатична комплексност

https://bg.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D1%84_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)

https://bg.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D1%84_(%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%BE%D1%82_%D0%B4%D0%B0%D0%BD%D0%BD%D0%B8)

http://trekto.info/algoritmi-strukturi-danni/7-darveta/

http://fmi.uni-plovdiv.bg/manev/Graphs/

M = E − N + 2P
Е – ребрата
N – възлите
P – броя графи, най-често 1, защото имаме само един граф

Що е polymorphism и има ли той почва у нас?

Полиморфизъм, поне в PHP имаме, когато имаме интерфейс, задаващ схемата на класовете, които го имплементират, и във отделните класове имаме един или повече метода, които правят различни неща според класа.

Но понеже името, и изобщо signature на такива методи е общ, се създава впечатление, че е един и същ метод, вършещ различни неща според класа си. А те реално са съвсем отделни методи.

According to the Polymorphism principle, methods in different classes that do similar things should have the same name.

Ето го примерният интерфейс:

interface Shape
{
    public function calcArea(); 
}

Ако имаме клас Circle implpements Shape или Square implements Shape, или каквъвто и да е shape… то за всеки клас, методът calcArea() ще върши различна работа.

Полиморфизмът в обектно ориентираното програмиране представлява свойството на обектите от един и същи интерфейс, но с различна реализация на този интерфейс да правят различни неща.

Това важи и за абстрактните класове – общите неща са отделени в абстрактният клас, но специфичните – според конкретния случай.

Различни неща или обекти могат да имат еднакъв интерфейс или да отговарят на едно и също (по наименование) съобщение и да реагират подходящо, в зависимост от природата или типа на обекта. Това позволява много различни неща да бъдат взаимозаменими. Например, ако една птица получи съобщение „движи се“, тя ще маха с крила и ще лети. Ако един лъв получи същото съобщение, той ще тича, използвайки краката си. И двете животни отговарят на една и съща команда по начини, които са свойствени за всяко от тях. Все едно два обекта, имплементиращи общ интерфейс, имплементирайки го по свой си начин.

Три са най-разпространените форми на полиморфизъм:

Ad hoc polymorphism или още Overloading

Различна имплементация на функция, на база на това какъв тип аргументи и се подава. Още е известен като „function overloading“ или „operator overloading“. Демек, това си е точно оверлоудване на функция. Ad hoc се използва, когато имаме например функции с едно име но различни имплементации, всеки за конкретен случай, и явно затова се казва ad hoc – „специално за“, „само за“.

program Adhoc;

function Add(x, y : Integer) : Integer;
begin
    Add := x + y
end;

function Add(s, t : String) : String;
begin
    Add := Concat(s, t)
end;

begin
    Writeln(Add(1, 2));                     (* Prints "3"               *)
    Writeln(Add('Hello, ', 'Mammals!'));    (* Prints "Hello, Mammals!" *)
end.

Subtyping

Тук се използва идеята, че чисто логически може типовете входни параметри и изходни резултати да се организират йерархично. Как програмно става това? Например, спазвайки SOLID принципа „Dependency Inversion Principle“, можем да използваме така да се каже по-общ тип, а не конкретен. Същата идея може да се реализира и с използването на абстрактен клас като тип.

Какво изобщо е „subtyping“? Помним „Liskov substitution principle“, e това е същото, но не за функции, а за типове. Демек, „родителският“ тип трябва да може да замества „детският“, бидейки негово „обобщение“. Както и „детският“ да замества „родителският“ бидейки негов „частен случай“.
Така се получава, че даден обект може да е от повече от един тип, като тези типове са йерархично организирани.

Идеята е да се даде по-широко поле на възможният тип, който може да се приема, но все пак да има някаква йерархия.

Authentication vs. Authorization

Authentication е все едно „логването“, тоест, да се легитимираш , най-често използвайки е-mail или потребителско име и парола, за да може сървът да провери дали има такъв регистиран и валиден потребител при него.

Authorization е дали при следващ request (следващ, демек след Authentication) наистина си ти, който си се логнал и ако да, да ти върна ли респонс.

При Authentication се сетва cookie с хедъра Set-Cookie с някакво session ID.

При Authorization клиентът, вече имайки това cookie, го изпраща с хедъра Cookie за да покаже кой е.

Но и не само това. В какъв смисъл?

В смисъл такъв, ОК влязъл си, искаш да првиш това или онова, но дали имаш право на това или онова? Това, че си влязъл не ти дава пълни права за всичко. Едно приложение има различни „области“, и различните потребители може да бъдат ограничени откъм права, според дадената област.

Демек, не само дали наистина си ти, който преди малко си се логнал, но и на ниво access level дали имаш право да правиш това и онова.

Authentication determines who you are, authorization determines what you can do.

Authentication verifies the identity of a user or service, and authorization determines their access rights.

After users are authenticated, authorization is a matter of determining what level of access authenticated users should have. For instance, the system admin of a web application has typically more access than a regular user.

Литература

https://identitymanagementinstitute.org/difference-between-authentication-and-authorization

READE.md

Анахронизъм от времената на ДОС и УНИКС.
Така някога са давали информация за дадена програма,
как се инсталира, копирайтс, изисквания…

Сега се използва малко, например от GitHub за да се даде плейн текст информация за дадена прогарама.

Изобщо, и сега се препоръчва, за да даде плейн текст инфо за дадена програма.

Но си е анахронизъм.

POSIX – що е то и има ли почва у нас?

Съвкупност от стандарти на IEEE, между различни Unix-like операционни системи, който да помогне съвместната им работа.

Какво е наложило налагането на тази съвкупност от стандарти?

Най-вероятно широкото нарояване на доста различни разновидности и дистрибуции на Unix операционни системи, чиито производители не са били склонни да си сътрудничат.

Литература:

https://en.wikipedia.org/wiki/POSIX

Hashig vs. Encrypting

Хеширането е едностранно, даден стринг например, веднъж хеширан, не може да се де-хешира. То е все едно една торта да я върнеш обратно до яйца, мляко, захар, брашно…

Енкриптването е двустранно, там идеята е веднъж екриптнат даден стринг например, да може да се декриптира обратно.