میخواهیم برنامهای بنویسیم تا بتوانیم با فایل نمرات دانشجویان کار کرده
و کارهایی که پیش از این توسط مسئولین آموزش به صورت دستی بر روی این فایلها
انجام میشد را خودکار کنیم. هر سطر از این فایل دارای سه بخش است که با
کاراکتر فاصله (`" "`) از هم جدا شدهاند. این سه بخش به ترتیب عبارتند از:
1. شماره دانشجویی (عدد صحیح)
2. کد درس (عدد صحیح)
3. نمره (عدد اعشاری)
یعنی هر سطر از این فایل مشخص میکند که یک دانشجو در یک درس چه نمرهای را
گرفته است.
چند نیاز اساسی در رابطه با این فایلها وجود دارد:
+ میخواهیم بتوانیم یک سطر دلخواه از این فایل را در قالب یک شئ از جنس کلاس `Grade` بخوانیم.
+ میخواهیم بتوانیم یک شئ از جنس `Grade` را به صورت یک سطر از فایل نمرات و در انتهای فایل ذخیره کنیم.
+ میخواهیم بتوانیم معدل دانشجویان در یک درس خاص را محاسبه کنیم.
+ میخواهیم بتوانیم معدل یک دانشجو را محاسبه کنیم.
# جزئیات
یک کلاس به نام `Grade` شامل سه خصوصیت با اسامی زیر بنویسید.
+ شماره دانشجویی: `student_id`
+ کد درس: `course_code`
+ نمره: `score`
کلاس شما باید دارای متد __construct باشد که این سه خصوصیت را به همین ترتیب دریافت و مقدار دهی کند.
با توجه به نیازمندیهایی که در بالا گفته شد، یک کلاس با نام `CourseUtil`
تعریف کنید که همه متدهای جدول زیر را طبق رفتار توضیح داده شده پیادهسازی کند.
| رفتار |خروجی| متد |
|:------------------:|:-------:|:-----------:|
|آدرس فایل نمرات به ورودی این متد داده میشود.|`-`| `set_file($address)`|
|یک شماره خط از فایل را در ورودی میگیرد و اطلاعات موجود در آن خط از فایل را در قالب یک شئ `Grade` برمیگرداند.|`Grade`| `load($line_number)`|
|یک شئ `Grade` در ورودی میگیرد و طبق فرمت مورد نظر، آن را در انتهای فایل اضافه میکند.|`-`|`save($grade)`|
|میانگین نمرات دانشجویان در درس با کد `course_code` را برمیگرداند. |`float`|`calc_course_average($course_code)`|
|میانگین نمرات دانشجو با شماره دانشجویی `student_id` در درسهای مختلف را برمیگرداند.|`float`|`calc_student_average($student_id)`|
|تعداد کل نمرات موجود در فایل نمرات را برمیگرداند.|`int`|`count()`|
# نکات
+ آدرس فایل با کمک متد `set_file` در اختیار کلاس قرار داده میشود. شما باید خودتان فایل را به نحوه دلخواه باز کنید. دقت کنید که فایل لزوما وجود ندارد. تنها زمانی میتوانید فرض کنید فایل وجود دارد که از شما خواسته شود یک خط از آن را بخوانید.
+ تضمین میشود در متد `load` شماره خطی که داده میشود حتما در فایل وجود دارد.
+ فرض کنید به جز برنامه شما، برنامههای دیگری نیز به فایل داده شده دسترسی دارند و ممکن است بین ۲ فراخوانی متوالی متدی مانند `load` محتویات فایل تغییر کرده باشد.
+ در فایل نمرات برای هر دانشجو در هر درس فقط یک نمره وجود دارد. بنابراین اگر برای دانشجو و درسی که نمره اش در فایل وجود دارد نمره جدیدی با متد `save` ثبت کنیم، نباید در فایل تغییری ایجاد شود.
+ در انتهای فایل `\n` وجود ندارد. شما نیز باید طوری فایل را تغییر دهید که هیچ گاه در انتهای فایل `\n` وجود نداشته باشد.
+ تضمین میشود که در هنگام محاسبه میانگینها شماره دانشجویی یا شماره درس داده شده در فایل موجود است.
+ تضمین می شود که مقدار وردی به عنوان `file_address$` مستقیما به عنوان ورودی توابع `file_get_contents` و `file_put_contents` قابل استفاده است.
در کد زیر یک فایل شامل دو سطر به عنوان ورودی داده شده است.
```php
$util = new CourseUtil();
$util->set_file($file_address);
echo $util->count();
$grade = new Grade(445612, 1234, 12);
$util->save($grade);
echo $util->count();
$util->set_file($file_address);
echo $util->count();
```
خروجی زیر مورد انتظار است:
```
2
3
3
```
#### آنچه باید آپلود کنید:
یک فایل Zip شامل یک فایل به نام `source.php` که کلاسهای `Grade` و `CourseUtil` در آن قرار دارد آپلود کنید.
منبع سؤال: مسابقات جاواکاپ
جهت ارائه ی اطلاعات شناسنامه ای یک فرد ، نیاز داریم آرایه ای به شکل زیر داشته باشیم :
```php
$person = [
'firstName' => 'Soobaasaa',
'lastName' => 'Ozaaraa',
'age' => 17,
'father' => [
'firstName' => 'Esaaro',
'lastName' => 'Ozaaraa',
'age' => 42
]
];
```
اما برای جلوگیری از نفوذ اطلاعات غلط به سیستم (مثلا کمتر بودن سن پدر از فرزند ، یا یکی نبودن نام خانوادگی پدر و فرزند) از ما خواسته شده که دو کلاس به نام های Person و Father را به شکلی طراحی کنیم که به صورت زیر قابل استفاده باشند :
```php
$father = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(42);
Person::firstName("Soobaasaa")->lastName( "Ozaaraa")->age(17)
->setFather( $father )-> toArray();
```
```php
// will output:
[
'firstName' => 'Soobaasaa',
'lastName' => 'Ozaaraa',
'age' => 17,
'father' => [
'firstName' => 'Esaaro',
'lastName' => 'Ozaaraa',
'age' => 42,
],
];
```
# جزئیات
شروطی که برای مشخصات پدر و فرزند مد نظر است عبارت اند از :
+ نام و نام خانوادگی باید از جنس string و حداقل 3 و حداکثر 15 حرف باشد و شامل کاراکترهای عددی نباشد.
مثلا : 'kaakero12'قابل قبول نیست
+ سن فرزند باید از جنس int و از 1 تا 130 باشد. (مثلا عدد 0 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)
+ سن پدر حداقل باید 18 و حداکثر 130 سال باشد. (مثلا عدد 17 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)
+ مقدار ورودی به متد setFatherباید یک objectاز کلاسFather باشد.
+ سن پدر و فرزند باید حداقل 18 سال تفاوت داشته باشد.
+ دقت کنید که سن پدر و فرزند هر دو باید معین باشد( فرزندی که سن نداشته باشد نمیتواند پدر داشته باشد و بلعکس)
+ نام خانوادگی lastName پدر و فرزند باید معین و یکسان باشند.
# نکات
ویژگی های کلاس های فوق :
+ متد firstName به عنوان اولین متد به صورت static و متد toArray به عنوان آخرین متد صدا زده می شوند و ترتیب صدا زدن بقیه متد ها اهمیتی ندارد.
+ اگر مقادیر ورودی به متد ها با شرط های بالا هم خوانی نداشتند از آن ها کاملا صرف نظر می شود و نباید باعث ایجاد هر گونه ارور شوند.
+ هر دو کلاس باید متدی به نام toArray داشته باشند که با صدا زدن آن در آخر، بتوان آرایه ای شامل اطلاعات فرد را به دست آورد.
```php
$f = Father::firstName('Esaaro')->lastName()->age(22) ->toArray();
// Will output :
[ 'firstName' => 'Esaaro' , 'age' => 22, ]
```
+ صدا زدن متد ها بدون مقدار ورودی نباید تاثیری در مقدار خروجی داشته باشد یا به هر ترتیب باعث ایجاد ارور شود.
```php
->lasName() // Does not cause any php errors.
```
+ برای سادگی کار فرض کنید هیچ گاه متدها را بیش از یک بار صدا نمی زنیم
```php
->lasName('foo')->lastName('Bar') // never happens
```
***
```php
$f = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(17)-> toArray();
// Will output :
[ 'firstName' => 'Esaaro', 'lastName' => 'Ozaaraa' ]
```
چون حداقل سن پدر باید 18 باشد مقدارage در خروجی مشاهده نمی شود.
***
```php
$f = Father::firstName('Esaaro')->lastName('222')->age(40)-> toArray();
// Will output :
[ 'firstName' => 'Esaaro', 'age' => 40 ],
```
چون نام خانوادگی نباید شامل عدد باشد مقدار lastName در خروجی مشاهده نمی شود.
***
```php
$fatherObj = Father::firstName('Esaaro') -> lastName('Ozaaraa') -> age(22);
Person::firstName('Soobaasaa') -> lastName('Ozaaraa') -> age(20) -> setFather( $fatherObj ) -> toArray();
// Will output :
[ 'firstName' => 'Soobaasaa' , 'lastName' => 'Ozaaraa', 'age' => 20, ]
```
در این مورد چون تفاوت سن پدر و پسر کمتر از 18 سال بوده پارامتر father در خروجی مشاهده نمی شود.
***
#### آنچه باید آپلود کنید:
یک فایل Zip شامل یک فایل به نام `solution.php` که کلاسهای `Father` و `Person` در آن قرار دارد.
یعنی هر دو کلاس داخل یک فایل تعریف شوند.
استفاده از trait ها در صورت مجاز و بلامانع است
## برای شروع کار میتوانید از لینک زیر یک فایل اولیه را دانلود کنید.
[solution.php](http://bayanbox.ir/info/576322194781329658/solution)